diff --git a/cmd/main.go b/cmd/main.go index 551df1a95..283202225 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -226,7 +226,7 @@ func main() { ruleBindingCache = rulebindingcachev1.NewCache(cfg, k8sClient, ruleCreator) rulesWatcher := ruleswatcher.NewRulesWatcher(k8sClient, ruleCreator, func() { ruleBindingCache.RefreshRuleBindingsRules() - }) + }, &cfg) dWatcher.AddAdaptor(rulesWatcher) } diff --git a/cmd/sign-object/main.go b/cmd/sign-object/main.go new file mode 100644 index 000000000..c803320b3 --- /dev/null +++ b/cmd/sign-object/main.go @@ -0,0 +1,550 @@ +package main + +import ( + "crypto/x509" + "encoding/base64" + "encoding/json" + "encoding/pem" + "flag" + "fmt" + "os" + "strings" + + k8syaml "k8s.io/apimachinery/pkg/util/yaml" + + rulemanagertypesv1 "github.com/kubescape/node-agent/pkg/rulemanager/types/v1" + "github.com/kubescape/node-agent/pkg/signature" + "github.com/kubescape/node-agent/pkg/signature/profiles" + "github.com/kubescape/storage/pkg/apis/softwarecomposition/v1beta1" + sigsyaml "sigs.k8s.io/yaml" +) + +var ( + inputFile string + outputFile string + keyFile string + objectType string + useKeyless bool + verbose bool + strict bool + jsonOutput bool + publicOnly bool + command string +) + +func main() { + if len(os.Args) < 2 { + printUsage() + os.Exit(1) + } + + command = os.Args[1] + + argsRewritten := false + if command == "-h" || command == "--help" { + printUsage() + os.Exit(0) + } + if strings.HasPrefix(command, "-") { + command = "sign" + argsRewritten = true + } + + switch command { + case "sign", "": + parseSignFlags() + if argsRewritten { + os.Args = append([]string{"sign-object"}, os.Args[1:]...) + } + case "verify": + parseVerifyFlags() + os.Args = append([]string{"sign-object verify"}, os.Args[2:]...) + case "generate-keypair": + parseGenerateFlags() + os.Args = append([]string{"sign-object generate-keypair"}, os.Args[2:]...) + case "extract-signature": + parseExtractFlags() + os.Args = append([]string{"sign-object extract-signature"}, os.Args[2:]...) + case "help", "--help", "-h": + printUsage() + os.Exit(0) + default: + fmt.Fprintf(os.Stderr, "Unknown command: %s\n", command) + printUsage() + os.Exit(1) + } + + if err := runCommand(); err != nil { + fmt.Fprintf(os.Stderr, "Error: %v\n", err) + os.Exit(1) + } +} + +func parseSignFlags() { + fs := flag.NewFlagSet("sign-object sign", flag.ExitOnError) + fs.StringVar(&inputFile, "file", "", "Input object YAML file (required)") + fs.StringVar(&outputFile, "output", "", "Output file for signed object (required)") + fs.StringVar(&keyFile, "key", "", "Path to private key file") + fs.StringVar(&objectType, "type", "auto", "Object type: applicationprofile, seccompprofile, networkneighborhood, rules, or auto") + fs.BoolVar(&useKeyless, "keyless", false, "Use keyless signing (OIDC)") + fs.BoolVar(&verbose, "verbose", false, "Enable verbose logging") + + offset := 2 + if len(os.Args) > 1 && strings.HasPrefix(os.Args[1], "-") { + offset = 1 + } + + if err := fs.Parse(os.Args[offset:]); err != nil { + fmt.Fprintf(os.Stderr, "Error parsing flags: %v\n", err) + os.Exit(1) + } + + if inputFile == "" { + fmt.Fprintln(os.Stderr, "Error: --file is required") + fs.PrintDefaults() + os.Exit(1) + } + + if outputFile == "" { + fmt.Fprintln(os.Stderr, "Error: --output is required") + fs.PrintDefaults() + os.Exit(1) + } + + if !useKeyless && keyFile == "" { + fmt.Fprintln(os.Stderr, "Error: either --keyless or --key must be specified") + fs.PrintDefaults() + os.Exit(1) + } +} + +func parseVerifyFlags() { + fs := flag.NewFlagSet("sign-object verify", flag.ExitOnError) + fs.StringVar(&inputFile, "file", "", "Signed object YAML file (required)") + fs.StringVar(&objectType, "type", "auto", "Object type: applicationprofile, seccompprofile, networkneighborhood, rules, or auto") + fs.BoolVar(&strict, "strict", true, "Require trusted issuer/identity") + fs.BoolVar(&verbose, "verbose", false, "Enable verbose logging") + + if err := fs.Parse(os.Args[2:]); err != nil { + fmt.Fprintf(os.Stderr, "Error parsing flags: %v\n", err) + os.Exit(1) + } + + if inputFile == "" { + fmt.Fprintln(os.Stderr, "Error: --file is required") + fs.PrintDefaults() + os.Exit(1) + } +} + +func parseGenerateFlags() { + fs := flag.NewFlagSet("sign-object generate-keypair", flag.ExitOnError) + fs.StringVar(&outputFile, "output", "", "Output PEM file") + fs.BoolVar(&publicOnly, "public-only", false, "Only output public key") + + if err := fs.Parse(os.Args[2:]); err != nil { + fmt.Fprintf(os.Stderr, "Error parsing flags: %v\n", err) + os.Exit(1) + } + + if outputFile == "" { + fmt.Fprintln(os.Stderr, "Error: --output is required") + fs.PrintDefaults() + os.Exit(1) + } +} + +func parseExtractFlags() { + fs := flag.NewFlagSet("sign-object extract-signature", flag.ExitOnError) + fs.StringVar(&inputFile, "file", "", "Signed object YAML file (required)") + fs.StringVar(&objectType, "type", "auto", "Object type: applicationprofile, seccompprofile, networkneighborhood, rules, or auto") + fs.BoolVar(&jsonOutput, "json", false, "Output as JSON") + + if err := fs.Parse(os.Args[2:]); err != nil { + fmt.Fprintf(os.Stderr, "Error parsing flags: %v\n", err) + os.Exit(1) + } + + if inputFile == "" { + fmt.Fprintln(os.Stderr, "Error: --file is required") + fs.PrintDefaults() + os.Exit(1) + } +} + +func runCommand() error { + switch command { + case "sign", "": + return runSign() + case "verify": + return runVerify() + case "generate-keypair": + return runGenerateKeyPair() + case "extract-signature": + return runExtractSignature() + default: + return fmt.Errorf("unknown command: %s", command) + } +} + +func runSign() error { + data, err := os.ReadFile(inputFile) + if err != nil { + return fmt.Errorf("failed to read input file: %w", err) + } + + if verbose { + fmt.Printf("Reading profile from: %s\n", inputFile) + fmt.Printf("Profile size: %d bytes\n", len(data)) + } + + profileAdapter, err := detectObjectType(objectType, data) + if err != nil { + return fmt.Errorf("failed to detect profile type: %w", err) + } + + if verbose { + fmt.Printf("Detected object type: %s\n", getObjectName(profileAdapter)) + } + + var signErr error + if useKeyless { + if verbose { + fmt.Println("Using keyless signing (OIDC)") + } + signErr = signature.SignObjectKeyless(profileAdapter) + } else { + if verbose { + fmt.Printf("Using local key from: %s\n", keyFile) + } + + keyData, err := os.ReadFile(keyFile) + if err != nil { + return fmt.Errorf("failed to read private key file: %w", err) + } + + block, _ := pem.Decode(keyData) + if block == nil { + return fmt.Errorf("failed to decode PEM block from key file") + } + + privateKey, err := x509.ParseECPrivateKey(block.Bytes) + if err != nil { + return fmt.Errorf("failed to parse EC private key: %w", err) + } + + signErr = signature.SignObject(profileAdapter, signature.WithPrivateKey(privateKey)) + } + + if signErr != nil { + return fmt.Errorf("failed to sign profile: %w", signErr) + } + + sig, err := signature.GetObjectSignature(profileAdapter) + if err != nil { + return fmt.Errorf("failed to get signature: %w", err) + } + + fmt.Printf("✓ Profile signed successfully\n") + fmt.Printf(" Issuer: %s\n", sig.Issuer) + fmt.Printf(" Identity: %s\n", sig.Identity) + fmt.Printf(" Timestamp: %d\n", sig.Timestamp) + + profileBytes, err := sigsyaml.Marshal(profileAdapter.GetUpdatedObject()) + if err != nil { + return fmt.Errorf("failed to marshal signed object: %w", err) + } + + if err := os.WriteFile(outputFile, profileBytes, 0644); err != nil { + return fmt.Errorf("failed to write output file: %w", err) + } + + fmt.Printf("✓ Signed profile written to: %s\n", outputFile) + return nil +} + +func runVerify() error { + data, err := os.ReadFile(inputFile) + if err != nil { + return fmt.Errorf("failed to read file: %w", err) + } + + if verbose { + fmt.Printf("Reading profile from: %s\n", inputFile) + } + + profileAdapter, err := detectObjectType(objectType, data) + if err != nil { + return fmt.Errorf("failed to detect profile type: %w", err) + } + + sig, err := signature.GetObjectSignature(profileAdapter) + if err != nil { + return fmt.Errorf("profile is not signed: %w", err) + } + + fmt.Printf("Signature found:\n") + fmt.Printf(" Issuer: %s\n", sig.Issuer) + fmt.Printf(" Identity: %s\n", sig.Identity) + fmt.Printf(" Timestamp: %d\n", sig.Timestamp) + + var verifyErr error + if strict { + if verbose { + fmt.Println("Verifying with strict mode (keyless signatures must have issuer/identity)") + } + verifyErr = signature.VerifyObjectStrict(profileAdapter) + } else { + if verbose { + fmt.Println("Verifying in non-strict mode (allowing untrusted signatures)") + } + verifyErr = signature.VerifyObjectAllowUntrusted(profileAdapter) + } + + if verifyErr != nil { + return fmt.Errorf("signature verification failed: %w", verifyErr) + } + + fmt.Printf("✓ Signature verification successful\n") + return nil +} + +func runGenerateKeyPair() error { + adapter, err := signature.NewCosignAdapter(false) + if err != nil { + return fmt.Errorf("failed to create adapter: %w", err) + } + + pubKeyBytes, err := adapter.GetPublicKeyPEM() + if err != nil { + return fmt.Errorf("failed to get public key: %w", err) + } + + if publicOnly { + if err := os.WriteFile(outputFile, pubKeyBytes, 0644); err != nil { + return fmt.Errorf("failed to write public key file: %w", err) + } + + fmt.Printf("✓ Public key written to: %s\n", outputFile) + return nil + } + + privKeyBytes, err := adapter.GetPrivateKeyPEM() + if err != nil { + return fmt.Errorf("failed to get private key: %w", err) + } + + if err := os.WriteFile(outputFile, privKeyBytes, 0600); err != nil { + return fmt.Errorf("failed to write private key file: %w", err) + } + + pubKeyFile := outputFile + ".pub" + if err := os.WriteFile(pubKeyFile, pubKeyBytes, 0644); err != nil { + return fmt.Errorf("failed to write public key file: %w", err) + } + + fmt.Printf("✓ Private key written to: %s\n", outputFile) + fmt.Printf("✓ Public key written to: %s\n", pubKeyFile) + return nil +} + +func runExtractSignature() error { + data, err := os.ReadFile(inputFile) + if err != nil { + return fmt.Errorf("failed to read file: %w", err) + } + + profileAdapter, err := detectObjectType(objectType, data) + if err != nil { + return fmt.Errorf("failed to detect profile type: %w", err) + } + + sig, err := signature.GetObjectSignature(profileAdapter) + if err != nil { + return fmt.Errorf("profile is not signed: %w", err) + } + + sigInfo := map[string]interface{}{ + "signature_size": len(sig.Signature), + "certificate_size": len(sig.Certificate), + "issuer": sig.Issuer, + "identity": sig.Identity, + "timestamp": sig.Timestamp, + "signature_base64": base64.StdEncoding.EncodeToString(sig.Signature), + "certificate_base64": base64.StdEncoding.EncodeToString(sig.Certificate), + } + + if jsonOutput { + jsonData, err := json.MarshalIndent(sigInfo, "", " ") + if err != nil { + return fmt.Errorf("failed to marshal JSON: %w", err) + } + fmt.Println(string(jsonData)) + } else { + fmt.Println("Signature Information:") + fmt.Printf(" Issuer: %s\n", sig.Issuer) + fmt.Printf(" Identity: %s\n", sig.Identity) + fmt.Printf(" Timestamp: %d\n", sig.Timestamp) + fmt.Printf(" Signature Size: %d bytes\n", len(sig.Signature)) + fmt.Printf(" Certificate Size: %d bytes\n", len(sig.Certificate)) + + block, _ := pem.Decode(sig.Certificate) + if block != nil { + fmt.Printf(" Certificate Type: %s\n", block.Type) + } + } + + return nil +} + +func detectObjectType(objectType string, data []byte) (signature.SignableObject, error) { + var decoded map[string]interface{} + if err := k8syaml.Unmarshal(data, &decoded); err != nil { + return nil, fmt.Errorf("failed to unmarshal YAML: %w", err) + } + + kind, _ := decoded["kind"].(string) + apiVersion, _ := decoded["apiVersion"].(string) + + if verbose { + fmt.Printf("Detected API: %s, Kind: %s\n", apiVersion, kind) + } + + if objectType != "auto" { + switch strings.ToLower(objectType) { + case "applicationprofile", "application-profile", "ap": + return loadApplicationProfile(data) + case "seccompprofile", "seccomp-profile", "sp": + return loadSeccompProfile(data) + case "networkneighborhood", "network-neighborhood", "nn": + return loadNetworkNeighborhood(data) + case "rules", "rule", "r": + return loadRules(data) + default: + return nil, fmt.Errorf("unknown object type: %s", objectType) + } + } + + if strings.Contains(strings.ToLower(apiVersion), "softwarecomposition") { + switch strings.ToLower(kind) { + case "applicationprofile", "application-profile": + return loadApplicationProfile(data) + case "seccompprofile", "seccomp-profile": + return loadSeccompProfile(data) + case "networkneighborhood", "network-neighborhood": + return loadNetworkNeighborhood(data) + } + } + + if strings.Contains(strings.ToLower(apiVersion), "kubescape.io") && strings.ToLower(kind) == "rules" { + return loadRules(data) + } + + return nil, fmt.Errorf("unable to auto-detect object type") +} + +func loadApplicationProfile(data []byte) (signature.SignableObject, error) { + var profile v1beta1.ApplicationProfile + if err := k8syaml.Unmarshal(data, &profile); err != nil { + return nil, fmt.Errorf("failed to unmarshal ApplicationProfile: %w", err) + } + return profiles.NewApplicationProfileAdapter(&profile), nil +} + +func loadSeccompProfile(data []byte) (signature.SignableObject, error) { + var profile v1beta1.SeccompProfile + if err := k8syaml.Unmarshal(data, &profile); err != nil { + return nil, fmt.Errorf("failed to unmarshal SeccompProfile: %w", err) + } + return profiles.NewSeccompProfileAdapter(&profile), nil +} + +func loadNetworkNeighborhood(data []byte) (signature.SignableObject, error) { + var nn v1beta1.NetworkNeighborhood + if err := k8syaml.Unmarshal(data, &nn); err != nil { + return nil, fmt.Errorf("failed to unmarshal NetworkNeighborhood: %w", err) + } + return profiles.NewNetworkNeighborhoodAdapter(&nn), nil +} + +func loadRules(data []byte) (signature.SignableObject, error) { + var rules rulemanagertypesv1.Rules + if err := k8syaml.Unmarshal(data, &rules); err != nil { + return nil, fmt.Errorf("failed to unmarshal Rules: %w", err) + } + return profiles.NewRulesAdapter(&rules), nil +} + +func getObjectName(profile signature.SignableObject) string { + if _, ok := profile.(*profiles.ApplicationProfileAdapter); ok { + return "ApplicationProfile" + } + if _, ok := profile.(*profiles.SeccompProfileAdapter); ok { + return "SeccompProfile" + } + if _, ok := profile.(*profiles.NetworkNeighborhoodAdapter); ok { + return "NetworkNeighborhood" + } + if _, ok := profile.(*profiles.RulesAdapter); ok { + return "Rules" + } + return "Unknown" +} + +func printUsage() { + fmt.Println(`sign-object - Sign and verify Kubernetes security objects + +USAGE: + sign-object [flags] + +COMMANDS: + sign Sign a profile (default command) + verify Verify a signed object + generate-keypair Generate a new ECDSA key pair + extract-signature Extract signature info from a profile + help Show this help message + +SIGN FLAGS: + --file Input object YAML file (required) + --output Output file for signed object (required) + --keyless Use keyless signing (OIDC) + --key Path to private key file + --type Object type: applicationprofile, seccompprofile, networkneighborhood, rules, or auto (default: auto) + --verbose Enable verbose logging + +VERIFY FLAGS: + --file Signed object YAML file (required) + --type Object type: applicationprofile, seccompprofile, networkneighborhood, rules, or auto (default: auto) + --strict Require trusted issuer/identity (default: true) + --verbose Enable verbose logging + +GENERATE-KEYPAIR FLAGS: + --output Output PEM file for private key (required) + --public-only Only output public key (no private key) + +EXTRACT-SIGNATURE FLAGS: + --file Signed object YAML file (required) + --type Object type: applicationprofile, seccompprofile, networkneighborhood, rules, or auto (default: auto) + --json Output as JSON + +EXAMPLES: + # Sign with keyless (OIDC) + sign-object --keyless --file object.yaml --output signed-object.yaml + + # Sign with local key + sign-object --key my-key.pem --file object.yaml --output signed-object.yaml + + # Verify a signed object + sign-object verify --file signed-object.yaml + + # Generate a key pair (writes my-key.pem and my-key.pem.pub) + sign-object generate-keypair --output my-key.pem + + # Generate only public key + sign-object generate-keypair --output my-key.pem --public-only + + # Extract signature information + sign-object extract-signature --file signed-object.yaml + +For more information, see: docs/signing/README.md`) +} diff --git a/docs/signing/README.md b/docs/signing/README.md new file mode 100644 index 000000000..c5cd4d165 --- /dev/null +++ b/docs/signing/README.md @@ -0,0 +1,610 @@ +# Object Signing Documentation + +## Overview + +The node-agent supports cryptographic signing of Kubernetes objects (profiles and rules) to ensure their integrity and authenticity. This feature uses signatures compatible with the **Sigstore/Cosign** ecosystem, leveraging official `sigstore/sigstore`, `sigstore/cosign`, and `sigstore/sigstore-go` libraries for robust blob signing and verification. + +Signed objects can be: +- **ApplicationProfiles** - defining allowed application behavior +- **SeccompProfiles** - defining allowed syscalls +- **NetworkNeighborhoods** - defining allowed network traffic +- **Rules** - defining security rules for the Rule Manager +- Any future object types that implement the `SignableObject` interface + +## Why Sign Objects? + +1. **Integrity** - Detect if an object has been tampered with +2. **Authenticity** - Verify who created the object +3. **Trust** - Establish a chain of trust for security policies +4. **Audit** - Track who signed what and when + +## Signature Verification + +The node-agent can automatically verify signatures when loading objects. This ensures that only trusted policies are enforced. + +### Enabling Verification + +Set the `enableSignatureVerification` configuration flag: + +```yaml +# config.json +{ + "enableSignatureVerification": true +} +``` + +Or via environment variable: + +```bash +export ENABLE_SIGNATURE_VERIFICATION=true +``` + +**Default:** `false` (verification disabled for backward compatibility) + +### Verification Behavior + +When verification is enabled: + +1. **ApplicationProfiles**: Verified in the ApplicationProfileCache when fetched from storage. +2. **SeccompProfiles**: Verified when fetched from storage. +3. **NetworkNeighborhoods**: Verified in the NetworkNeighborhoodCache when fetched from storage. +4. **Rules**: Verified by the RulesWatcher when syncing from the cluster. + +On **verification failure**: +- Object is **skipped** (not loaded or processed) +- Warning is logged with object namespace, name, and error +- Enforcement continues (doesn't crash the agent) + +This ensures security while maintaining availability - if an object can't be verified, the node-agent continues operating with other valid objects. + +## Architecture + +### Canonical Hashing + +To ensure the signature remains valid regardless of minor YAML formatting differences or the presence of the signature itself, we use **Canonical Hashing**. + +1. **Sanitization**: Before hashing, the object is "sanitized" by creating a copy that excludes the `metadata.annotations`, `metadata.managedFields`, and the `status` block. +2. **Canonical JSON**: The sanitized object is marshaled to JSON. +3. **Hashing**: We use `github.com/kubescape/storage/pkg/utils.CanonicalHash` which performs a specialized SHA-256 hash of the JSON. + +**Key Finding:** `CanonicalHash` includes all fields in its input. Therefore, the **sanitization step is mandatory** to prevent a circular dependency where adding the signature annotation changes the hash and invalidates the signature. + +### Diagram +```mermaid +graph TB + subgraph "Signing Flow" + A[K8s Resource] --> B[Adapter] + B --> C[SignableObject Interface] + C --> D[GetContent: Sanitized JSON] + D --> E{Signing Mode} + E -->|Keyless| F[Sigstore: OIDC + Fulcio + Rekor] + E -->|Key-based| G[Local ECDSA Signer] + F --> H[Signature + Cert + RekorBundle] + G --> H[Signature + Public Key] + H --> I[Base64 Encode] + I --> J[Object Annotations] + J --> K[GetUpdatedObject: Live Resource] + K --> L[Signed Object YAML] + end + + subgraph "Verification Flow" + M[Signed Object] --> N[Extract Signature] + M --> O[Extract Cert/Key] + M --> P[Extract RekorBundle] + M --> Q[GetContent: Sanitized JSON] + Q --> R[Sigstore Verifier] + N --> R + O --> R + P --> R + R --> S{Valid?} + S -->|Yes| T[Object accepted] + S -->|No| U[Object rejected] + end + + L --> M +``` + +## Annotation Format + +Signed objects store signature information in these annotations: + +```yaml +metadata: + annotations: + signature.kubescape.io/signature: "base64-encoded-signature" + signature.kubescape.io/certificate: "base64-encoded-cert-or-pubkey" + signature.kubescape.io/rekor-bundle: "base64-encoded-rekor-bundle" + signature.kubescape.io/issuer: "https://token.actions.githubusercontent.com" + signature.kubescape.io/identity: "kubernetes.io" + signature.kubescape.io/timestamp: "1709894400" +``` + +### Annotation Keys + +| Key | Description | Example | +|-----|-------------|---------| +| `signature.kubescape.io/signature` | Base64-encoded ECDSA signature | `MEUCIQD...` | +| `signature.kubescape.io/certificate` | Base64-encoded x509 cert or public key | `MFkwEwY...` | +| `signature.kubescape.io/rekor-bundle` | Base64-encoded Rekor transparency log bundle | `eyJzaWdu...` | +| `signature.kubescape.io/issuer` | OIDC issuer (for keyless) | `https://token.actions.githubusercontent.com` | +| `signature.kubescape.io/identity` | Signing identity | `kubernetes.io` or `local-key` | +| `signature.kubescape.io/timestamp` | Unix timestamp of signing | `1709894400` | + +## Signing Modes + +### Keyless Signing (Recommended) + +Uses OIDC identity providers like GitHub Actions, Google, or Kubernetes. No need to manage private keys. + +```bash +sign-object \ + --keyless \ + --file my-app-profile.yaml \ + --output signed-profile.yaml +``` + +**Advantages:** +- No private key management +- Built-in identity verification +- Compatible with CI/CD pipelines +- Audit trail from OIDC providers + +### Key-Based Signing + +Uses a locally generated ECDSA P-256 key pair. Useful for: +- Offline signing +- Air-gapped environments +- Testing and development + +```bash +# Generate a key pair (one-time) +sign-object generate-keypair --output my-key-pair.pem + +# Sign with the key +sign-object \ + --key my-key-pair.pem \ + --file my-app-profile.yaml \ + --output signed-profile.yaml +``` + +## CLI Reference + +### Installation + +```bash +# Build from source +cd cmd/sign-object +go build -o sign-object + +# Or install globally +go install github.com/kubescape/node-agent/cmd/sign-object@latest +``` + +### Commands + +#### `sign-object [sign]` + +Sign a Kubernetes object. + +```bash +sign-object [sign] [flags] +``` + +**Flags:** + +| Flag | Type | Default | Description | +|------|------|---------|-------------| +| `--file` | string | required | Input object YAML file | +| `--output` | string | required | Output file for signed object | +| `--keyless` | bool | false | Use keyless signing (OIDC) | +| `--key` | string | - | Path to private key file | +| `--type` | string | auto | Object type: `applicationprofile`, `seccompprofile`, `networkneighborhood`, `rules`, or `auto` | +| `--verbose` | bool | false | Enable verbose logging | + +**Examples:** + +```bash +# Sign with keyless (OIDC) +sign-object --keyless --file app-profile.yaml --output signed-app-profile.yaml + +# Sign with local key +sign-object --key my-key.pem --file seccomp-profile.yaml --output signed-seccomp.yaml + +# Sign Rules CRD +sign-object --keyless --file rules.yaml --output signed-rules.yaml + +# Auto-detect object type +sign-object --keyless --file object.yaml --output signed.yaml + +# Specify object type explicitly +sign-object --keyless --type seccompprofile --file profile.yaml --output signed.yaml +``` + +#### `sign-object verify` + +Verify a signed object's signature. + +```bash +sign-object verify [flags] +``` + +**Flags:** + +| Flag | Type | Default | Description | +|------|------|---------|-------------| +| `--file` | string | required | Signed object YAML file | +| `--type` | string | auto | Object type: `applicationprofile`, `seccompprofile`, `networkneighborhood`, `rules`, or `auto` | +| `--strict` | bool | true | Require trusted issuer/identity | +| `--verbose` | bool | false | Enable verbose logging | + +**Examples:** + +```bash +# Verify with strict checking (keyless must have issuer/identity) +sign-object verify --file signed-object.yaml + +# Allow untrusted local signatures +sign-object verify --file signed-object.yaml --strict=false +``` + +#### `sign-object generate-keypair` + +Generate a new ECDSA P-256 key pair for local signing. + +```bash +sign-object generate-keypair [flags] +``` + +**Flags:** + +| Flag | Type | Default | Description | +|------|------|---------|-------------| +| `--output` | string | - | Path for the private key file (writes `FILE` for private key and `FILE.pub` for public key) | +| `--public-only` | bool | false | Only write the public key (writes only to `FILE`, no `.pub` suffix) | + +**Examples:** + +```bash +# Generate full key pair +sign-object generate-keypair --output my-signing-key.pem + +# Generate only public key (for verification only) +sign-object generate-keypair --public-only --output public-key.pem +``` + +#### `sign-object extract-signature` + +Extract signature information from a signed object. + +```bash +sign-object extract-signature [flags] +``` + +**Flags:** + +| Flag | Type | Default | Description | +|------|------|---------|-------------| +| `--file` | string | required | Signed object YAML file | +| `--type` | string | auto | Object type: `applicationprofile`, `seccompprofile`, `networkneighborhood`, `rules`, or `auto` | +| `--json` | bool | false | Output as JSON | + +**Examples:** + +```bash +# Display signature info +sign-object extract-signature --file signed-object.yaml + +# Output as JSON for scripting +sign-object extract-signature --file signed-object.yaml --json +``` + +## Complete Workflow + +### Example 1: Sign ApplicationProfile with Keyless + +```bash +# 1. Create your ApplicationProfile +cat > my-app-profile.yaml << 'EOF' +apiVersion: softwarecomposition.kubescape.io/v1beta1 +kind: ApplicationProfile +metadata: + name: nginx-profile + namespace: default +spec: + architectures: + - amd64 + containers: + - name: nginx + capabilities: + - CAP_NET_BIND_SERVICE + execs: + - path: /usr/sbin/nginx +EOF + +# 2. Sign with keyless +sign-object --keyless \ + --file my-app-profile.yaml \ + --output signed-app-profile.yaml + +# 3. Apply to cluster +kubectl apply -f signed-app-profile.yaml + +# 4. Verify anytime +sign-object verify --file signed-app-profile.yaml +``` + +### Example 2: Sign SeccompProfile with Local Key + +```bash +# 1. Generate key pair +sign-object generate-keypair --output seccomp-signing-key.pem + +# 2. Create SeccompProfile +cat > my-seccomp-profile.yaml << 'EOF' +apiVersion: softwarecomposition.kubescape.io/v1beta1 +kind: SeccompProfile +metadata: + name: strict-seccomp + namespace: default +spec: + containers: + - name: app-container +EOF + +# 3. Sign with local key +sign-object --key seccomp-signing-key.pem \ + --file my-seccomp-profile.yaml \ + --output signed-seccomp-profile.yaml + +# 4. Verify +sign-object verify --file signed-seccomp-profile.yaml +``` + +### Example 3: Sign Rules CRD + +```bash +# 1. Create Rules CRD +cat > my-rules.yaml << 'EOF' +apiVersion: kubescape.io/v1 +kind: Rules +metadata: + name: my-security-rules + namespace: kubescape +spec: + rules: + - id: R0001 + enabled: true + name: "Suspicious Exec" + parameters: + paths: ["/bin/bash"] +EOF + +# 2. Sign with keyless +sign-object --keyless \ + --file my-rules.yaml \ + --output signed-rules.yaml + +# 3. Verify +sign-object verify --file signed-rules.yaml +``` + +### Example 4: Sign NetworkNeighborhood with Keyless + +```bash +# 1. Create NetworkNeighborhood +cat > my-nn.yaml << 'EOF' +apiVersion: softwarecomposition.kubescape.io/v1beta1 +kind: NetworkNeighborhood +metadata: + name: nginx-nn + namespace: default +spec: + containers: + - name: nginx + egress: + - identifier: "dns:8.8.8.8" + ipAddress: "8.8.8.8" + ports: + - port: 53 + protocol: UDP +EOF + +# 2. Sign with keyless +sign-object --keyless \ + --file my-nn.yaml \ + --output signed-nn.yaml + +# 3. Verify +sign-object verify --file signed-nn.yaml +``` + +### Example 5: Batch Signing in CI/CD + +```yaml +# .github/workflows/sign-objects.yml +name: Sign Security Objects + +on: + push: + paths: + - 'policies/**.yaml' + +jobs: + sign: + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + + steps: + - uses: actions/checkout@v4 + + - name: Install sign-object + run: | + cd cmd/sign-object + go build -o sign-object + + - name: Sign Objects + run: | + for obj in policies/*.yaml; do + ./sign-object --keyless \ + --file "$obj" \ + --output "signed/$(basename $obj)" + done + + - name: Verify all signed objects + run: | + for obj in signed/*.yaml; do + ./sign-object verify --file "$obj" + done + + - name: Upload signed objects + uses: actions/upload-artifact@v4 + with: + name: signed-objects + path: signed/*.yaml +``` + +## Security Model + +```mermaid +sequenceDiagram + participant Admin + participant CLI + participant Signer + participant Object + participant Cluster + participant Verifier + + Admin->>CLI: sign-object --keyless + CLI->>Signer: Initialize Sigstore Signer + CLI->>Object: Marshal content to JSON + CLI->>Signer: Sign content + Signer->>Signer: Sign with Sigstore + Signer-->>CLI: Return signature + certificate + CLI->>Object: Add signature annotations + Object-->>Admin: Signed object YAML + + Admin->>Cluster: kubectl apply signed-object.yaml + Cluster->>Verifier: Verify signature + Verifier->>Verifier: Extract content & signature/cert + Verifier->>Verifier: Verify with Sigstore + Verifier-->>Cluster: Valid ✓ + Cluster-->>Admin: Object applied +``` + +## Threat Model + +| Threat | Mitigation | +|--------|------------| +| Object tampering | ECDSA signature verification | +| Impersonation | OIDC identity verification (keyless) | +| Key compromise | Short-lived keys, rotation support | +| Replay attacks | Timestamps, uniqueness checks | +| Man-in-the-middle | Certificate pinning, verification | + +## Best Practices + +1. **Enable Verification in Production** + - Set `enableSignatureVerification: true` in node-agent config + - Objects failing verification are skipped with warnings + - Doesn't crash the agent - maintains availability + +2. **Use Keyless Signing in Production** + - No private keys to manage + - Built-in identity from GitHub Actions/Google/Kubernetes + - Transparent, auditable signing process + +3. **Sign Before Applying** + - Always verify signatures before applying to clusters + - Enable cache verification in node-agent for automatic validation + - Consider admission controller to enforce verification + +4. **Version Your Objects** + - Include version in metadata + - Old signatures become invalid on content changes + +5. **Key Management for Local Signing** + - Store keys in secure locations (HSM, KMS) + - Rotate keys regularly + - Use read-only keys for verification + +6. **Audit Trail** + - Store signing timestamps + - Track who signed what + - Use GitHub Actions for audit logs + +## Troubleshooting + +### Verification Fails + +```bash +# Check if object was modified +sign-object extract-signature --file object.yaml + +# Verify with verbose output +sign-object verify --file object.yaml --verbose +``` + +### Missing Annotation + +```bash +# This error means no signature annotation found +# Ensure you're using the signed version of the object +``` + +### OIDC Token Issues + +```bash +# For keyless signing, ensure OIDC token is available +# In GitHub Actions: permissions: id-token: write +# In local environment: configure gcloud or kubectl +``` + +## Integration with Admission Controllers + +For clusters that require verified objects, use an admission webhook: + +```yaml +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: object-signature-verifier +webhooks: +- name: verify-object-signature.kubescape.io + rules: + - apiGroups: ["softwarecomposition.kubescape.io"] + apiVersions: ["v1beta1"] + operations: ["CREATE", "UPDATE"] + resources: ["applicationprofiles", "seccompprofiles"] + - apiGroups: ["kubescape.io"] + apiVersions: ["v1"] + operations: ["CREATE", "UPDATE"] + resources: ["rules"] + sideEffects: None + admissionReviewVersions: ["v1"] +``` + +The webhook would: +1. Extract signature from annotations +2. Verify signature against object content +3. Reject if signature invalid or missing + +## Key Files + +| `pkg/signature/interface.go` | SignableObject interface and Signature struct | +| `pkg/signature/cosign_adapter.go` | Sigstore/Cosign signing and verification | +| `pkg/signature/sign.go` | Public signing API and annotation encoding | +| `pkg/signature/verify.go` | Public verification API and cache integration | +| `pkg/signature/profiles/applicationprofile_adapter.go` | ApplicationProfile adapter | +| `pkg/signature/profiles/seccompprofile_adapter.go` | SeccompProfile adapter | +| `pkg/signature/profiles/networkneighborhood_adapter.go` | NetworkNeighborhood adapter | +| `pkg/signature/profiles/rules_adapter.go` | Rules adapter | +| `cmd/sign-object/main.go` | CLI tool for object signing | + +## Additional Resources + +- [Sigstore Documentation](https://docs.sigstore.dev/) +- [Cosign Project](https://github.com/sigstore/cosign) +- [Kubernetes Security Best Practices](https://kubernetes.io/docs/concepts/security/) +- [OIDC for Kubernetes](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#openid-connect-tokens) diff --git a/go.mod b/go.mod index d5a5b412b..1d2b42150 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/kubescape/node-agent -go 1.25.0 +go 1.25.5 require ( github.com/DmitriyVTitov/size v1.5.0 @@ -21,7 +21,8 @@ require ( github.com/dustin/go-humanize v1.0.1 github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb - github.com/go-openapi/strfmt v0.23.0 + github.com/go-openapi/strfmt v0.25.0 + github.com/golang-jwt/jwt/v5 v5.3.0 github.com/google/cel-go v0.26.1 github.com/google/go-containerregistry v0.20.7 github.com/google/uuid v1.6.0 @@ -46,38 +47,42 @@ require ( github.com/prometheus/alertmanager v0.27.0 github.com/prometheus/client_golang v1.23.2 github.com/prometheus/procfs v0.19.2 - github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af + github.com/sigstore/cosign/v3 v3.0.5 + github.com/sigstore/fulcio v1.8.5 + github.com/sigstore/rekor v1.5.0 + github.com/sigstore/sigstore v1.10.4 + github.com/sirupsen/logrus v1.9.4 github.com/spf13/afero v1.15.0 github.com/spf13/viper v1.21.0 github.com/stretchr/testify v1.11.1 github.com/weaveworks/procspy v0.0.0-20150706124340-cb970aa190c3 go.uber.org/multierr v1.11.0 - golang.org/x/net v0.48.0 + golang.org/x/net v0.49.0 golang.org/x/sys v0.40.0 gonum.org/v1/plot v0.14.0 - google.golang.org/grpc v1.77.0 + google.golang.org/grpc v1.78.0 gopkg.in/mcuadros/go-syslog.v2 v2.3.0 istio.io/pkg v0.0.0-20231221211216-7635388a563e - k8s.io/api v0.35.0 - k8s.io/apimachinery v0.35.0 - k8s.io/client-go v0.35.0 + k8s.io/api v0.35.1 + k8s.io/apimachinery v0.35.1 + k8s.io/client-go v0.35.1 k8s.io/cri-api v0.35.0 k8s.io/kubectl v0.34.1 k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 - modernc.org/sqlite v1.38.2 + modernc.org/sqlite v1.40.1 oras.land/oras-go/v2 v2.6.0 sigs.k8s.io/yaml v1.6.0 ) require ( cel.dev/expr v0.24.0 // indirect - cloud.google.com/go v0.121.3 // indirect - cloud.google.com/go/auth v0.16.2 // indirect + cloud.google.com/go v0.123.0 // indirect + cloud.google.com/go/auth v0.18.1 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect cloud.google.com/go/compute/metadata v0.9.0 // indirect - cloud.google.com/go/iam v1.5.2 // indirect - cloud.google.com/go/monitoring v1.24.2 // indirect - cloud.google.com/go/storage v1.55.0 // indirect + cloud.google.com/go/iam v1.5.3 // indirect + cloud.google.com/go/monitoring v1.24.3 // indirect + cloud.google.com/go/storage v1.59.1 // indirect cyphar.com/go-pathrs v0.2.1 // indirect dario.cat/mergo v1.0.2 // indirect git.sr.ht/~sbinet/gg v0.5.0 // indirect @@ -89,8 +94,8 @@ require ( github.com/CycloneDX/cyclonedx-go v0.9.2 // indirect github.com/DataDog/zstd v1.5.7 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 // indirect - github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 // indirect - github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/sprig/v3 v3.3.0 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect @@ -125,7 +130,7 @@ require ( github.com/armosec/gojay v1.2.17 // indirect github.com/armosec/utils-go v0.0.58 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect - github.com/aws/aws-sdk-go v1.55.7 // indirect + github.com/aws/aws-sdk-go v1.55.8 // indirect github.com/aws/aws-sdk-go-v2 v1.41.1 // indirect github.com/aws/aws-sdk-go-v2/config v1.32.7 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.19.7 // indirect @@ -154,6 +159,10 @@ require ( github.com/bodgit/sevenzip v1.6.1 // indirect github.com/bodgit/windows v1.0.1 // indirect github.com/briandowns/spinner v1.23.2 // indirect + github.com/buildkite/agent/v3 v3.115.4 // indirect + github.com/buildkite/go-pipeline v0.16.0 // indirect + github.com/buildkite/interpolate v0.1.5 // indirect + github.com/buildkite/roko v1.4.0 // indirect github.com/campoy/embedmd v1.0.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/charmbracelet/colorprofile v0.3.1 // indirect @@ -181,20 +190,23 @@ require ( github.com/containers/common v0.64.2 // indirect github.com/coreos/go-oidc/v3 v3.17.0 // indirect github.com/coreos/go-systemd/v22 v22.6.0 // indirect + github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/deitch/magic v0.0.0-20240306090643-c67ab88f10cb // indirect + github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 // indirect + github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 // indirect github.com/diskfs/go-diskfs v1.7.0 // indirect github.com/distribution/reference v0.6.0 // indirect github.com/docker/cli v29.1.3+incompatible // indirect github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/docker v28.5.2+incompatible // indirect - github.com/docker/docker-credential-helpers v0.9.3 // indirect + github.com/docker/docker-credential-helpers v0.9.4 // indirect github.com/docker/go-connections v0.6.0 // indirect github.com/docker/go-events v0.0.0-20250114142523-c867878c5e32 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect github.com/elliotchance/phpserialize v1.4.0 // indirect - github.com/emicklei/go-restful/v3 v3.12.2 // indirect + github.com/emicklei/go-restful/v3 v3.13.0 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/envoyproxy/go-control-plane/envoy v1.35.0 // indirect github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect @@ -206,10 +218,11 @@ require ( github.com/francoispqt/gojay v1.2.13 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fxamacker/cbor/v2 v2.9.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.10 // indirect + github.com/gabriel-vasile/mimetype v1.4.11 // indirect github.com/gammazero/deque v1.0.0 // indirect github.com/github/go-spdx/v2 v2.3.3 // indirect github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect + github.com/go-chi/chi/v5 v5.2.4 // indirect github.com/go-errors/errors v1.5.1 // indirect github.com/go-fonts/liberation v0.3.2 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect @@ -220,15 +233,26 @@ require ( github.com/go-ldap/ldap/v3 v3.4.10 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-openapi/analysis v0.23.0 // indirect - github.com/go-openapi/errors v0.22.2 // indirect - github.com/go-openapi/jsonpointer v0.21.2 // indirect - github.com/go-openapi/jsonreference v0.21.0 // indirect - github.com/go-openapi/loads v0.22.0 // indirect - github.com/go-openapi/runtime v0.28.0 // indirect - github.com/go-openapi/spec v0.21.0 // indirect - github.com/go-openapi/swag v0.23.1 // indirect - github.com/go-openapi/validate v0.24.0 // indirect + github.com/go-openapi/analysis v0.24.1 // indirect + github.com/go-openapi/errors v0.22.6 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/jsonreference v0.21.4 // indirect + github.com/go-openapi/loads v0.23.2 // indirect + github.com/go-openapi/runtime v0.29.2 // indirect + github.com/go-openapi/spec v0.22.3 // indirect + github.com/go-openapi/swag v0.25.4 // indirect + github.com/go-openapi/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/conv v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // indirect + github.com/go-openapi/validate v0.25.1 // indirect github.com/go-pdf/fpdf v0.9.0 // indirect github.com/go-restruct/restruct v1.2.0-alpha // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect @@ -236,49 +260,53 @@ require ( github.com/godbus/dbus/v5 v5.2.0 // indirect github.com/gofrs/flock v0.13.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/gohugoio/hashstructure v0.5.0 // indirect + github.com/gohugoio/hashstructure v0.6.0 // indirect github.com/golang-jwt/jwt/v4 v4.5.2 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/golang/snappy v1.0.0 // indirect github.com/google/btree v1.1.3 // indirect + github.com/google/certificate-transparency-go v1.3.2 // indirect github.com/google/gnostic-models v0.7.0 // indirect github.com/google/go-cmp v0.7.0 // indirect + github.com/google/go-querystring v1.2.0 // indirect github.com/google/licensecheck v0.3.1 // indirect github.com/google/pprof v0.0.0-20250630185457-6e76a2b096b5 // indirect github.com/google/s2a-go v0.1.9 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect - github.com/googleapis/gax-go/v2 v2.15.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.11 // indirect + github.com/googleapis/gax-go/v2 v2.17.0 // indirect github.com/gookit/color v1.6.0 // indirect github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.5 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-getter v1.7.9 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-retryablehttp v0.7.8 // indirect github.com/hashicorp/go-safetemp v1.0.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/hashicorp/hcl/v2 v2.24.0 // indirect github.com/huandu/xstrings v1.5.0 // indirect github.com/iancoleman/strcase v0.3.0 // indirect + github.com/in-toto/attestation v1.1.2 // indirect github.com/in-toto/in-toto-golang v0.9.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect + github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 // indirect github.com/jinzhu/copier v0.4.0 // indirect - github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/josharian/intern v1.0.0 // indirect + github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 // indirect github.com/josharian/native v1.1.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect - github.com/klauspost/compress v1.18.1 // indirect + github.com/klauspost/compress v1.18.2 // indirect github.com/klauspost/pgzip v1.2.6 // indirect + github.com/letsencrypt/boulder v0.20251110.0 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mackerelio/go-osstat v0.2.5 // indirect - github.com/mailru/easyjson v0.9.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect @@ -291,7 +319,6 @@ require ( github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // 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/locker v1.0.1 // indirect @@ -315,33 +342,36 @@ require ( github.com/notaryproject/notation-go v1.3.2 // indirect github.com/notaryproject/notation-plugin-framework-go v1.0.0 // indirect github.com/notaryproject/tspclient-go v1.0.0 // indirect + github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 // indirect github.com/nwaples/rardecode v1.1.3 // indirect github.com/nwaples/rardecode/v2 v2.1.1 // indirect github.com/oklog/ulid v1.3.1 // indirect + github.com/oleiade/reflections v1.1.0 // indirect github.com/olekukonko/errors v1.1.0 // indirect github.com/olekukonko/ll v0.0.9 // indirect - github.com/olekukonko/tablewriter v1.0.9 // indirect + github.com/olekukonko/tablewriter v1.1.0 // indirect github.com/olvrng/ujson v1.1.0 // indirect github.com/opcoder0/capabilities v0.0.0-20221222060822-17fd73bffd2a // indirect github.com/opencontainers/runtime-spec v1.2.1 // indirect github.com/opencontainers/selinux v1.13.1 // indirect - github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect github.com/packetcap/go-pcap v0.0.0-20250723190045-d00b185f30b7 // indirect github.com/pborman/indent v1.2.1 // indirect + github.com/pborman/uuid v1.2.1 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/petermattis/goid v0.0.0-20241211131331-93ee7e083c43 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/pjbgf/sha1cd v0.4.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pkg/profile v1.7.0 // indirect github.com/pkg/xattr v0.4.12 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.67.4 // indirect - github.com/puzpuzpuz/xsync/v2 v2.4.1 // indirect + github.com/prometheus/common v0.67.5 // indirect + github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/rust-secure-code/go-rustaudit v0.0.0-20250226111315-e20ec32e963c // indirect @@ -350,14 +380,17 @@ require ( github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect github.com/sasha-s/go-deadlock v0.3.5 // indirect github.com/sassoftware/go-rpmutils v0.4.0 // indirect + github.com/sassoftware/relic v7.2.1+incompatible // indirect github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e // indirect github.com/seccomp/libseccomp-golang v0.11.0 // indirect - github.com/secure-systems-lab/go-securesystemslib v0.9.1 // indirect + github.com/secure-systems-lab/go-securesystemslib v0.10.0 // indirect github.com/sergi/go-diff v1.4.0 // indirect github.com/shibumi/go-pathspec v1.3.0 // indirect github.com/shopspring/decimal v1.4.0 // indirect github.com/sigstore/protobuf-specs v0.5.0 // indirect - github.com/sigstore/sigstore v1.10.4 // indirect + github.com/sigstore/rekor-tiles/v2 v2.2.0 // indirect + github.com/sigstore/sigstore-go v1.1.4 // indirect + github.com/sigstore/timestamp-authority/v2 v2.0.4 // indirect github.com/skeema/knownhosts v1.3.1 // indirect github.com/sorairolake/lzip-go v0.3.7 // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect @@ -373,7 +406,13 @@ require ( github.com/subosito/gotenv v1.6.0 // indirect github.com/sylabs/sif/v2 v2.22.0 // indirect github.com/sylabs/squashfs v1.0.6 // indirect + github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/therootcompany/xz v1.0.1 // indirect + github.com/theupdateframework/go-tuf v0.7.0 // indirect + github.com/theupdateframework/go-tuf/v2 v2.4.1 // indirect + github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect + github.com/transparency-dev/formats v0.0.0-20251017110053-404c0d5b696c // indirect + github.com/transparency-dev/merkle v0.0.2 // indirect github.com/ulikunitz/xz v0.5.15 // indirect github.com/uptrace/opentelemetry-go-extra/otelutil v0.3.2 // indirect github.com/uptrace/opentelemetry-go-extra/otelzap v0.3.2 // indirect @@ -393,18 +432,18 @@ require ( github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect github.com/yl2chen/cidranger v1.0.2 // indirect github.com/zclconf/go-cty v1.16.3 // indirect - go.mongodb.org/mongo-driver v1.17.4 // indirect + go.mongodb.org/mongo-driver v1.17.6 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/detectors/gcp v1.38.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect go.opentelemetry.io/contrib/instrumentation/runtime v0.64.0 // indirect go.opentelemetry.io/otel v1.40.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 // indirect go.opentelemetry.io/otel/log v0.15.0 // indirect go.opentelemetry.io/otel/metric v1.40.0 // indirect @@ -413,26 +452,26 @@ require ( go.opentelemetry.io/otel/sdk/metric v1.40.0 // indirect go.opentelemetry.io/otel/trace v1.40.0 // indirect go.opentelemetry.io/proto/otlp v1.9.0 // indirect - go.uber.org/zap v1.27.0 // indirect + go.uber.org/zap v1.27.1 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect go4.org v0.0.0-20230225012048-214862532bf5 // indirect go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect - golang.org/x/crypto v0.46.0 // indirect - golang.org/x/exp v0.0.0-20250718183923-645b1fa84792 // indirect + golang.org/x/crypto v0.47.0 // indirect + golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect golang.org/x/image v0.18.0 // indirect - golang.org/x/mod v0.30.0 // indirect - golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/mod v0.32.0 // indirect + golang.org/x/oauth2 v0.35.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/term v0.38.0 // indirect - golang.org/x/text v0.32.0 // indirect + golang.org/x/term v0.39.0 // indirect + golang.org/x/text v0.33.0 // indirect golang.org/x/time v0.14.0 // indirect - golang.org/x/tools v0.39.0 // indirect + golang.org/x/tools v0.40.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect - google.golang.org/api v0.242.0 // indirect - google.golang.org/genproto v0.0.0-20250715232539-7130f93afb79 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect + google.golang.org/api v0.267.0 // indirect + google.golang.org/genproto v0.0.0-20260128011058-8636f8732409 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20 // indirect google.golang.org/protobuf v1.36.11 // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect @@ -446,7 +485,7 @@ require ( k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect k8s.io/kubelet v0.35.0 // indirect - modernc.org/libc v1.66.3 // indirect + modernc.org/libc v1.66.10 // indirect modernc.org/mathutil v1.7.1 // indirect modernc.org/memory v1.11.0 // indirect sigs.k8s.io/controller-runtime v0.21.0 // indirect diff --git a/go.sum b/go.sum index d81485b14..516545f08 100644 --- a/go.sum +++ b/go.sum @@ -41,8 +41,8 @@ cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRY cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= -cloud.google.com/go v0.121.3 h1:84RD+hQXNdY5Sw/MWVAx5O9Aui/rd5VQ9HEcdN19afo= -cloud.google.com/go v0.121.3/go.mod h1:6vWF3nJWRrEUv26mMB3FEIU/o1MQNVPG1iHdisa2SJc= +cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE= +cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU= cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= @@ -104,8 +104,8 @@ cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVo cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= -cloud.google.com/go/auth v0.16.2 h1:QvBAGFPLrDeoiNjyfVunhQ10HKNYuOwZ5noee0M5df4= -cloud.google.com/go/auth v0.16.2/go.mod h1:sRBas2Y1fB1vZTdurouM0AzuYQBMZinrUYL8EufhtEA= +cloud.google.com/go/auth v0.18.1 h1:IwTEx92GFUo2pJ6Qea0EU3zYvKnTAeRCODxfA/G5UWs= +cloud.google.com/go/auth v0.18.1/go.mod h1:GfTYoS9G3CWpRA3Va9doKN9mjPGRS+v41jmZAhBzbrA= cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= @@ -323,8 +323,8 @@ cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGE cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY= cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= -cloud.google.com/go/iam v1.5.2 h1:qgFRAGEmd8z6dJ/qyEchAuL9jpswyODjA2lS+w234g8= -cloud.google.com/go/iam v1.5.2/go.mod h1:SE1vg0N81zQqLzQEwxL2WI6yhetBdbNQuTvIKCSkUHE= +cloud.google.com/go/iam v1.5.3 h1:+vMINPiDF2ognBJ97ABAYYwRgsaqxPbQDlMnbHMjolc= +cloud.google.com/go/iam v1.5.3/go.mod h1:MR3v9oLkZCTlaqljW6Eb2d3HGDGK5/bDv93jhfISFvU= cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= @@ -344,6 +344,8 @@ cloud.google.com/go/kms v1.8.0/go.mod h1:4xFEhYFqvW+4VMELtZyxomGSYtSQKzM178ylFW4 cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= cloud.google.com/go/kms v1.10.0/go.mod h1:ng3KTUtQQU9bPX3+QGLsflZIHlkbn8amFAMY63m8d24= cloud.google.com/go/kms v1.10.1/go.mod h1:rIWk/TryCkR59GMC3YtHtXeLzd634lBbKenvyySAyYI= +cloud.google.com/go/kms v1.25.0 h1:gVqvGGUmz0nYCmtoxWmdc1wli2L1apgP8U4fghPGSbQ= +cloud.google.com/go/kms v1.25.0/go.mod h1:XIdHkzfj0bUO3E+LvwPg+oc7s58/Ns8Nd8Sdtljihbk= cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= @@ -354,13 +356,13 @@ cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6 cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= -cloud.google.com/go/logging v1.13.0 h1:7j0HgAp0B94o1YRDqiqm26w4q1rDMH7XNRU34lJXHYc= -cloud.google.com/go/logging v1.13.0/go.mod h1:36CoKh6KA/M0PbhPKMq6/qety2DCAErbhXT62TuXALA= +cloud.google.com/go/logging v1.13.1 h1:O7LvmO0kGLaHY/gq8cV7T0dyp6zJhYAOtZPX4TF3QtY= +cloud.google.com/go/logging v1.13.1/go.mod h1:XAQkfkMBxQRjQek96WLPNze7vsOmay9H5PqfsNYDqvw= cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= -cloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE= -cloud.google.com/go/longrunning v0.6.7/go.mod h1:EAFV3IZAKmM56TyiE6VAP3VoTzhZzySwI/YI1s/nRsY= +cloud.google.com/go/longrunning v0.8.0 h1:LiKK77J3bx5gDLi4SMViHixjD2ohlkwBi+mKA7EhfW8= +cloud.google.com/go/longrunning v0.8.0/go.mod h1:UmErU2Onzi+fKDg2gR7dusz11Pe26aknR4kHmJJqIfk= cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= @@ -384,8 +386,8 @@ cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhI cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= cloud.google.com/go/monitoring v1.13.0/go.mod h1:k2yMBAB1H9JT/QETjNkgdCGD9bPF712XiLTVr+cBrpw= -cloud.google.com/go/monitoring v1.24.2 h1:5OTsoJ1dXYIiMiuL+sYscLc9BumrL3CarVLL7dd7lHM= -cloud.google.com/go/monitoring v1.24.2/go.mod h1:x7yzPWcgDRnPEv3sI+jJGBkwl5qINf+6qY4eq0I9B4U= +cloud.google.com/go/monitoring v1.24.3 h1:dde+gMNc0UhPZD1Azu6at2e79bfdztVDS5lvhOdsgaE= +cloud.google.com/go/monitoring v1.24.3/go.mod h1:nYP6W0tm3N9H/bOw8am7t62YTzZY+zUeQ+Bi6+2eonI= cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= @@ -549,8 +551,8 @@ cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeL cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= -cloud.google.com/go/storage v1.55.0 h1:NESjdAToN9u1tmhVqhXCaCwYBuvEhZLLv0gBr+2znf0= -cloud.google.com/go/storage v1.55.0/go.mod h1:ztSmTTwzsdXe5syLVS0YsbFxXuvEmEyZj7v7zChEmuY= +cloud.google.com/go/storage v1.59.1 h1:DXAZLcTimtiXdGqDSnebROVPd9QvRsFVVlptz02Wk58= +cloud.google.com/go/storage v1.59.1/go.mod h1:cMWbtM+anpC74gn6qjLh+exqYcfmB9Hqe5z6adx+CLI= cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= @@ -570,8 +572,8 @@ cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= cloud.google.com/go/trace v1.9.0/go.mod h1:lOQqpE5IaWY0Ixg7/r2SjixMuc6lfTFeO4QGM4dQWOk= -cloud.google.com/go/trace v1.11.6 h1:2O2zjPzqPYAHrn3OKl029qlqG6W8ZdYaOWRyr8NgMT4= -cloud.google.com/go/trace v1.11.6/go.mod h1:GA855OeDEBiBMzcckLPE2kDunIpC72N+Pq8WFieFjnI= +cloud.google.com/go/trace v1.11.7 h1:kDNDX8JkaAG3R2nq1lIdkb7FCSi1rCmsEtKVsty7p+U= +cloud.google.com/go/trace v1.11.7/go.mod h1:TNn9d5V3fQVf6s4SCveVMIBS2LJUqo73GACmq/Tky0s= cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= cloud.google.com/go/translate v1.5.0/go.mod h1:29YDSYveqqpA1CQFD7NQuP49xymq17RXNaUDdc0mNu0= @@ -627,6 +629,8 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7 dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= +filippo.io/edwards25519 v1.1.1 h1:YpjwWWlNmGIDyXOn8zLzqiD+9TyIlPhGFG96P39uBpw= +filippo.io/edwards25519 v1.1.1/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= git.sr.ht/~sbinet/cmpimg v0.1.0 h1:E0zPRk2muWuCqSKSVZIWsgtU9pjsw3eKHi8VmQeScxo= @@ -638,10 +642,25 @@ github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8af github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20250520111509-a70c2aa677fa h1:x6kFzdPgBoLbyoNkA/jny0ENpoEz4wqY8lPTQL2DPkg= github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20250520111509-a70c2aa677fa/go.mod h1:gCLVsLfv1egrcZu+GoJATN5ts75F2s62ih/457eWzOw= +github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230919221257-8b5d3ce2d11d h1:zjqpY4C7H15HjRPEenkS4SAn3Jy2eRRjkjZbGR30TOg= +github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230919221257-8b5d3ce2d11d/go.mod h1:XNqJ7hv2kY++g8XEHREpi+JqZo3+0l+CH2egBVN4yqM= +github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 h1:fou+2+WFTib47nS+nz/ozhEBnvU96bKHy6LjRsY4E28= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0/go.mod h1:t76Ruy8AHvUAC8GfMWJMa0ElSbuIcO03NLpynfbgsPA= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 h1:Hk5QBxZQC1jb2Fwj6mpzme37xbCDdNTxU7O9eb5+LB4= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1/go.mod h1:IYus9qsFobWIc2YVwe/WPjcnyCkPKtnHAqUYeebc8z0= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 h1:9iefClla7iYpfYWdzPCRDozdmndjTm8DXdpCzPajMgA= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2/go.mod h1:XtLgD3ZD34DAaVIIAyG3objl5DynM3CQ/vMcbBNJZGI= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.4.0 h1:E4MgwLBGeVB5f2MdcIVD3ELVAWpr+WD6MUe1i+tM/PA= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.4.0/go.mod h1:Y2b/1clN4zsAoUd/pgNAQHjLDnTis/6ROkUfyob6psM= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0 h1:nCYfgcSyHZXJI8J0IWE5MsCGlb2xp9fJiXyxWgmOFg4= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0/go.mod h1:ucUjca2JtSZboY8IoUqyQyuuXvwbMBVwFOm0vdQPNhA= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 h1:XRzhVemXdgvJqCH0sFfrBUTnUJSBrBf7++ypk+twtRs= +github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= @@ -656,12 +675,12 @@ github.com/DmitriyVTitov/size v1.5.0 h1:/PzqxYrOyOUX1BXj6J9OuVRVGe+66VL4D9FlUaW5 github.com/DmitriyVTitov/size v1.5.0/go.mod h1:le6rNI4CoLQV1b9gzp1+3d7hMAD/uu2QcJ+aYbNgiU0= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 h1:sBEjpZlNHzK1voKq9695PJSX2o5NEXl7/OL3coiIY0c= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 h1:owcC2UnmsZycprQ5RfRgjydWhuoxg71LUfyiQdijZuM= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0/go.mod h1:ZPpqegjbE99EPKsu3iUWV22A04wzGPcAY/ziSIQEEgs= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.53.0 h1:4LP6hvB4I5ouTbGgWtixJhgED6xdf67twf9PoY96Tbg= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.53.0/go.mod h1:jUZ5LYlw40WMd07qxcQJD5M40aUxrfwqQX1g7zxYnrQ= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 h1:Ron4zCA/yk6U7WOBXhTJcDpsUBG9npumK6xw2auFltQ= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0/go.mod h1:cSgYe11MCNYunTnRXrKiR/tHc0eoKjICUuWpNZoVCOo= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0 h1:lhhYARPUu3LmHysQ/igznQphfzynnqI3D75oUyw1HXk= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0/go.mod h1:l9rva3ApbBpEJxSNYnwT9N4CDLrWgtq3u8736C5hyJw= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.54.0 h1:xfK3bbi6F2RDtaZFtUdKO3osOBIhNb+xTs8lFW6yx9o= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.54.0/go.mod h1:vB2GH9GAYYJTO3mEn8oYwzEdhlayZIdQz6zdzgUIRvA= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0 h1:s0WlVbf9qpvkh1c/uDAPElam0WrL7fHRIidgZJ7UqZI= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0/go.mod h1:Mf6O40IAyB9zR/1J8nGDDPirZQQPbYJni8Yisy7NTMc= github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= @@ -698,6 +717,8 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy 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/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= +github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/anchore/archiver/v3 v3.5.3-0.20241210171143-5b1d8d1c7c51 h1:yhk+P8lF3ZiROjmaVRao9WGTRo4b/wYjoKEiAHWrKwc= @@ -774,8 +795,8 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:W github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= -github.com/aws/aws-sdk-go v1.55.7 h1:UJrkFq7es5CShfBwlWAC8DA077vp8PyVbQd3lqLiztE= -github.com/aws/aws-sdk-go v1.55.7/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= +github.com/aws/aws-sdk-go v1.55.8 h1:JRmEUbU52aJQZ2AjX4q4Wu7t4uZjOu71uyNmaWlUkJQ= +github.com/aws/aws-sdk-go v1.55.8/go.mod h1:ZkViS9AqA6otK+JBBNH2++sx1sgxrPKcSzPPvQkUtXk= github.com/aws/aws-sdk-go-v2 v1.41.1 h1:ABlyEARCDLN034NhxlRUSZr4l71mh+T5KAeGh6cerhU= github.com/aws/aws-sdk-go-v2 v1.41.1/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0= github.com/aws/aws-sdk-go-v2/config v1.32.7 h1:vxUyWGUwmkQ2g19n7JY/9YL8MfAIl7bTesIUykECXmY= @@ -796,6 +817,8 @@ github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEd github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 h1:RuNSMoozM8oXlgLG/n6WLaFGoea7/CddrCfIiSA+xdY= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17/go.mod h1:F2xxQ9TZz5gDWsclCtPQscGpP0VUOc8RqgFM3vDENmU= +github.com/aws/aws-sdk-go-v2/service/kms v1.49.5 h1:DKibav4XF66XSeaXcrn9GlWGHos6D/vJ4r7jsK7z5CE= +github.com/aws/aws-sdk-go-v2/service/kms v1.49.5/go.mod h1:1SdcmEGUEQE1mrU2sIgeHtcMSxHuybhPvuEPANzIDfI= github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 h1:VrhDvQib/i0lxvr3zqlUwLwJP4fpmpyD9wYG1vfSu+Y= github.com/aws/aws-sdk-go-v2/service/signin v1.0.5/go.mod h1:k029+U8SY30/3/ras4G/Fnv/b88N4mAfliNn08Dem4M= github.com/aws/aws-sdk-go-v2/service/sso v1.30.9 h1:v6EiMvhEYBoHABfbGB4alOYmCIrcgyPPiBE1wZAEbqk= @@ -841,6 +864,14 @@ github.com/bradleyjkemp/cupaloy/v2 v2.8.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1l github.com/briandowns/spinner v1.23.2 h1:Zc6ecUnI+YzLmJniCfDNaMbW0Wid1d5+qcTq4L2FW8w= github.com/briandowns/spinner v1.23.2/go.mod h1:LaZeM4wm2Ywy6vO571mvhQNRcWfRUnXOs0RcKV0wYKM= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/buildkite/agent/v3 v3.115.4 h1:oxuLAjwHADBlTZuTrTb0JPt0FBcbGo55ZqDHPJ0jn+E= +github.com/buildkite/agent/v3 v3.115.4/go.mod h1:LKY99ujcnFwX8ihEXuMLuPIy3SPL2unKWGJ/DRLICr0= +github.com/buildkite/go-pipeline v0.16.0 h1:wEgWUMRAgSg1ZnWOoA3AovtYYdTvN0dLY1zwUWmPP+4= +github.com/buildkite/go-pipeline v0.16.0/go.mod h1:VE37qY3X5pmAKKUMoDZvPsHOQuyakB9cmXj9Qn6QasA= +github.com/buildkite/interpolate v0.1.5 h1:v2Ji3voik69UZlbfoqzx+qfcsOKLA61nHdU79VV+tPU= +github.com/buildkite/interpolate v0.1.5/go.mod h1:dHnrwHew5O8VNOAgMDpwRlFnhL5VSN6M1bHVmRZ9Ccc= +github.com/buildkite/roko v1.4.0 h1:DxixoCdpNqxu4/1lXrXbfsKbJSd7r1qoxtef/TT2J80= +github.com/buildkite/roko v1.4.0/go.mod h1:0vbODqUFEcVf4v2xVXRfZZRsqJVsCCHTG/TBRByGK4E= github.com/campoy/embedmd v1.0.0 h1:V4kI2qTJJLf4J29RzI/MAt2c3Bl4dQSYPuflzwFH2hY= github.com/campoy/embedmd v1.0.0/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX3MzVl8= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= @@ -956,8 +987,12 @@ github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/crewjam/rfc5424 v0.1.0 h1:MSeXJm22oKovLzWj44AHwaItjIMUMugYGkEzfa831H8= github.com/crewjam/rfc5424 v0.1.0/go.mod h1:RCi9M3xHVOeerf6ULZzqv2xOGRO/zYaVUeRyPnBW3gQ= +github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 h1:uX1JmpONuD549D73r6cgnxyUu18Zb7yHAy5AYU0Pm4Q= +github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw= github.com/cyphar/filepath-securejoin v0.6.0 h1:BtGB77njd6SVO6VztOHfPxKitJvd/VPT+OFBFMOi1Is= github.com/cyphar/filepath-securejoin v0.6.0/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc= +github.com/danieljoos/wincred v1.2.3 h1:v7dZC2x32Ut3nEfRH+vhoZGvN72+dQ/snVXo/vMFLdQ= +github.com/danieljoos/wincred v1.2.3/go.mod h1:6qqX0WNrS4RzPZ1tnroDzq9kY3fu1KwE7MRLQK4X0bs= 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= @@ -969,6 +1004,11 @@ github.com/deitch/magic v0.0.0-20240306090643-c67ab88f10cb/go.mod h1:B3tI9iGHi4i github.com/dghubble/trie v0.1.0 h1:kJnjBLFFElBwS60N4tkPvnLhnpcDxbBjIulgI8CpNGM= github.com/dghubble/trie v0.1.0/go.mod h1:sOmnzfBNH7H92ow2292dDFWNsVQuh/izuD7otCYb1ak= github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4= +github.com/digitorus/pkcs7 v0.0.0-20230713084857-e76b763bdc49/go.mod h1:SKVExuS+vpu2l9IoOc0RwqE7NYnb0JlcFHFnEJkVDzc= +github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 h1:ge14PCmCvPjpMQMIAH7uKg0lrtNSOdpYsRXlwk3QbaE= +github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352/go.mod h1:SKVExuS+vpu2l9IoOc0RwqE7NYnb0JlcFHFnEJkVDzc= +github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 h1:lxmTCgmHE1GUYL7P0MlNa00M67axePTq+9nBSGddR8I= +github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7/go.mod h1:GvWntX9qiTlOud0WkQ6ewFm0LPy5JUR1Xo0Ngbd1w6Y= github.com/diskfs/go-diskfs v1.7.0 h1:vonWmt5CMowXwUc79jWyGrf2DIMeoOjkLlMnQYGVOs8= github.com/diskfs/go-diskfs v1.7.0/go.mod h1:LhQyXqOugWFRahYUSw47NyZJPezFzB9UELwhpszLP/k= github.com/distribution/distribution v2.8.2+incompatible h1:k9+4DKdOG+quPFZXT/mUsiQrGu9vYCp+dXpuPkuqhk8= @@ -983,8 +1023,8 @@ github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBi github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM= github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8= -github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo= +github.com/docker/docker-credential-helpers v0.9.4 h1:76ItO69/AP/V4yT9V4uuuItG0B1N8hvt0T0c0NN/DzI= +github.com/docker/docker-credential-helpers v0.9.4/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c= github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE= github.com/docker/go-events v0.0.0-20250114142523-c867878c5e32 h1:EHZfspsnLAz8Hzccd67D5abwLiqoqym2jz/jOS39mCk= @@ -1006,8 +1046,8 @@ github.com/elliotchance/phpserialize v1.4.0 h1:cAp/9+KSnEbUC8oYCE32n2n84BeW8HOY3 github.com/elliotchance/phpserialize v1.4.0/go.mod h1:gt7XX9+ETUcLXbtTKEuyrqW3lcLUAeS/AnGZ2e49TZs= github.com/elliotwutingfeng/asciiset v0.0.0-20230602022725-51bbb787efab h1:h1UgjJdAAhj+uPL68n7XASS6bU+07ZX1WJvVS2eyoeY= github.com/elliotwutingfeng/asciiset v0.0.0-20230602022725-51bbb787efab/go.mod h1:GLo/8fDswSAniFG+BFIaiSPcK610jyzgEhWYPQwuQdw= -github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU= -github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes= +github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -1066,13 +1106,15 @@ github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09 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.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= -github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0= -github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= +github.com/gabriel-vasile/mimetype v1.4.11 h1:AQvxbp830wPhHTqc1u7nzoLT+ZFxGY7emj5DR5DYFik= +github.com/gabriel-vasile/mimetype v1.4.11/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= github.com/gammazero/deque v1.0.0 h1:LTmimT8H7bXkkCy6gZX7zNLtkbz4NdS2z8LZuor3j34= github.com/gammazero/deque v1.0.0/go.mod h1:iflpYvtGfM3U8S8j+sZEKIak3SAKYpA5/SQewgfXDKo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -1085,6 +1127,8 @@ github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= github.com/go-asn1-ber/asn1-ber v1.5.7 h1:DTX+lbVTWaTw1hQ+PbZPlnDZPEIs0SS/GCZAl535dDk= github.com/go-asn1-ber/asn1-ber v1.5.7/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-chi/chi/v5 v5.2.4 h1:WtFKPHwlywe8Srng8j2BhOD9312j9cGUxG1SP4V2cR4= +github.com/go-chi/chi/v5 v5.2.4/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= @@ -1129,26 +1173,54 @@ 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-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= -github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU= -github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo= -github.com/go-openapi/errors v0.22.2 h1:rdxhzcBUazEcGccKqbY1Y7NS8FDcMyIRr0934jrYnZg= -github.com/go-openapi/errors v0.22.2/go.mod h1:+n/5UdIqdVnLIJ6Q9Se8HNGUXYaY6CN8ImWzfi/Gzp0= -github.com/go-openapi/jsonpointer v0.21.2 h1:AqQaNADVwq/VnkCmQg6ogE+M3FOsKTytwges0JdwVuA= -github.com/go-openapi/jsonpointer v0.21.2/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk= -github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= -github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/loads v0.22.0 h1:ECPGd4jX1U6NApCGG1We+uEozOAvXvJSF4nnwHZ8Aco= -github.com/go-openapi/loads v0.22.0/go.mod h1:yLsaTCS92mnSAZX5WWoxszLj0u+Ojl+Zs5Stn1oF+rs= -github.com/go-openapi/runtime v0.28.0 h1:gpPPmWSNGo214l6n8hzdXYhPuJcGtziTOgUpvsFWGIQ= -github.com/go-openapi/runtime v0.28.0/go.mod h1:QN7OzcS+XuYmkQLw05akXk0jRH/eZ3kb18+1KwW9gyc= -github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= -github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= -github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c= -github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4= -github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= -github.com/go-openapi/validate v0.24.0 h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3BumrGD58= -github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ= +github.com/go-openapi/analysis v0.24.1 h1:Xp+7Yn/KOnVWYG8d+hPksOYnCYImE3TieBa7rBOesYM= +github.com/go-openapi/analysis v0.24.1/go.mod h1:dU+qxX7QGU1rl7IYhBC8bIfmWQdX4Buoea4TGtxXY84= +github.com/go-openapi/errors v0.22.6 h1:eDxcf89O8odEnohIXwEjY1IB4ph5vmbUsBMsFNwXWPo= +github.com/go-openapi/errors v0.22.6/go.mod h1:z9S8ASTUqx7+CP1Q8dD8ewGH/1JWFFLX/2PmAYNQLgk= +github.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= +github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= +github.com/go-openapi/loads v0.23.2 h1:rJXAcP7g1+lWyBHC7iTY+WAF0rprtM+pm8Jxv1uQJp4= +github.com/go-openapi/loads v0.23.2/go.mod h1:IEVw1GfRt/P2Pplkelxzj9BYFajiWOtY2nHZNj4UnWY= +github.com/go-openapi/runtime v0.29.2 h1:UmwSGWNmWQqKm1c2MGgXVpC2FTGwPDQeUsBMufc5Yj0= +github.com/go-openapi/runtime v0.29.2/go.mod h1:biq5kJXRJKBJxTDJXAa00DOTa/anflQPhT0/wmjuy+0= +github.com/go-openapi/spec v0.22.3 h1:qRSmj6Smz2rEBxMnLRBMeBWxbbOvuOoElvSvObIgwQc= +github.com/go-openapi/spec v0.22.3/go.mod h1:iIImLODL2loCh3Vnox8TY2YWYJZjMAKYyLH2Mu8lOZs= +github.com/go-openapi/strfmt v0.25.0 h1:7R0RX7mbKLa9EYCTHRcCuIPcaqlyQiWNPTXwClK0saQ= +github.com/go-openapi/strfmt v0.25.0/go.mod h1:nNXct7OzbwrMY9+5tLX4I21pzcmE6ccMGXl3jFdPfn8= +github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= +github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= +github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= +github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= +github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= +github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= +github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= +github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= +github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= +github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= +github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= +github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= +github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= +github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= +github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= +github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= +github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= +github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= +github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= +github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= +github.com/go-openapi/validate v0.25.1 h1:sSACUI6Jcnbo5IWqbYHgjibrhhmt3vR6lCzKZnmAgBw= +github.com/go-openapi/validate v0.25.1/go.mod h1:RMVyVFYte0gbSTaZ0N4KmTn6u/kClvAFp+mAVfS/DQc= github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/go-pdf/fpdf v0.9.0 h1:PPvSaUuo1iMi9KkaAn90NuKi+P4gwMedWPHhj8YlJQw= @@ -1157,8 +1229,14 @@ github.com/go-quicktest/qt v1.101.1-0.20240301121107-c6c8733fa1e6 h1:teYtXy9B7y5 github.com/go-quicktest/qt v1.101.1-0.20240301121107-c6c8733fa1e6/go.mod h1:p4lGIVX+8Wa6ZPNDvqcxq36XpUDLh42FLetFU7odllI= github.com/go-restruct/restruct v1.2.0-alpha h1:2Lp474S/9660+SJjpVxoKuWX09JsXHSrdV7Nv3/gkvc= github.com/go-restruct/restruct v1.2.0-alpha/go.mod h1:KqrpKpn4M8OLznErihXTGLlsXFGeLxHUrLRRI/1YjGk= +github.com/go-rod/rod v0.116.2 h1:A5t2Ky2A+5eD/ZJQr1EfsQSe5rms5Xof/qj296e+ZqA= +github.com/go-rod/rod v0.116.2/go.mod h1:H+CMO9SCNc2TJ2WfrG+pKhITz57uGNYU43qYHh438Mg= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo= +github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= @@ -1180,10 +1258,12 @@ github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8 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/gohugoio/hashstructure v0.5.0 h1:G2fjSBU36RdwEJBWJ+919ERvOVqAg9tfcYp47K9swqg= -github.com/gohugoio/hashstructure v0.5.0/go.mod h1:Ser0TniXuu/eauYmrwM4o64EBvySxNzITEOLlm4igec= +github.com/gohugoio/hashstructure v0.6.0 h1:7wMB/2CfXoThFYhdWRGv3u3rUM761Cq29CxUW+NltUg= +github.com/gohugoio/hashstructure v0.6.0/go.mod h1:lapVLk9XidheHG1IQ4ZSbyYrXcaILU1ZEP/+vno5rBQ= github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= +github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -1235,6 +1315,8 @@ 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/cel-go v0.26.1 h1:iPbVVEdkhTX++hpe3lzSk7D3G3QSYqLGoHOcEio+UXQ= github.com/google/cel-go v0.26.1/go.mod h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PUIaryMM= +github.com/google/certificate-transparency-go v1.3.2 h1:9ahSNZF2o7SYMaKaXhAumVEzXB2QaayzII9C8rv7v+A= +github.com/google/certificate-transparency-go v1.3.2/go.mod h1:H5FpMUaGa5Ab2+KCYsxg6sELw3Flkl7pGZzWdBoYLXs= github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= @@ -1260,7 +1342,11 @@ github.com/google/go-containerregistry v0.20.7 h1:24VGNpS0IwrOZ2ms2P1QE3Xa5X9p4p github.com/google/go-containerregistry v0.20.7/go.mod h1:Lx5LCZQjLH1QBaMPeGwsME9biPeo1lPx6lbGj/UmzgM= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/go-querystring v1.2.0 h1:yhqkPbu2/OH+V9BfpCVPZkNmUXhb2gBxJArfhIxNtP0= +github.com/google/go-querystring v1.2.0/go.mod h1:8IFJqpSRITyJ8QhQ13bmbeMBDfmeEJZD5A0egEOmkqU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/licensecheck v0.3.1 h1:QoxgoDkaeC4nFrtGN1jV7IPmDCHFNIVh54e5hSt6sPs= github.com/google/licensecheck v0.3.1/go.mod h1:ORkR35t/JjW+emNKtfJDII0zlciG9JgbT7SmsohlHmY= github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= @@ -1283,6 +1369,7 @@ github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= @@ -1293,6 +1380,9 @@ github.com/google/pprof v0.0.0-20250630185457-6e76a2b096b5/go.mod h1:5hDyRhoBCxV github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= +github.com/google/trillian v1.7.2 h1:EPBxc4YWY4Ak8tcuhyFleY+zYlbCDCa4Sn24e1Ka8Js= +github.com/google/trillian v1.7.2/go.mod h1:mfQJW4qRH6/ilABtPYNBerVJAJ/upxHLX81zxNQw05s= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -1302,8 +1392,8 @@ github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4= -github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= +github.com/googleapis/enterprise-certificate-proxy v0.3.11 h1:vAe81Msw+8tKUxi2Dqh/NZMz7475yUvmRIkXr4oN2ao= +github.com/googleapis/enterprise-certificate-proxy v0.3.11/go.mod h1:RFV7MUdlb7AgEq2v7FmMCfeSMCllAzWxFgRdusoGks8= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -1317,8 +1407,8 @@ github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqE github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= -github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo= -github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc= +github.com/googleapis/gax-go/v2 v2.17.0 h1:RksgfBpxqff0EZkDWYuz9q/uWsTVz+kf43LsZ1J6SMc= +github.com/googleapis/gax-go/v2 v2.17.0/go.mod h1:mzaqghpQp4JDh3HvADwrat+6M3MOIDp5YKHhb9PAgDY= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gookit/assert v0.1.1 h1:lh3GcawXe/p+cU7ESTZ5Ui3Sm/x8JWpIis4/1aF0mY0= @@ -1342,12 +1432,14 @@ github.com/grafana/pyroscope-go/godeltaprof v0.1.8/go.mod h1:2+l7K7twW49Ct4wFluZ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.5 h1:jP1RStw811EvUDzsUQ9oESqw2e4RqCjSAD9qIL8eMns= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.5/go.mod h1:WXNBZ64q3+ZUemCMXD9kYnr56H7CgZxDBHCVwstfl3s= github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= 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= @@ -1361,6 +1453,8 @@ github.com/hashicorp/go-getter v1.7.9 h1:G9gcjrDixz7glqJ+ll5IWvggSBR+R0B54DSRt4q github.com/hashicorp/go-getter v1.7.9/go.mod h1:dyFCmT1AQkDfOIt9NH8pw9XBDqNrIKJT5ylbpi7zPNE= github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= @@ -1369,10 +1463,19 @@ github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48= +github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.2.0 h1:U+kC2dOhMFQctRfhK0gRctKAPTloZdMU5ZJxaesJ/VM= +github.com/hashicorp/go-secure-stdlib/parseutil v0.2.0/go.mod h1:Ll013mhdmsVDuoIXVfBtvgGJsXDYkTw1kooNcoCXuE0= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-sockaddr v1.0.7 h1:G+pTkSO01HpR5qCxg7lxfsFEZaG+C0VssTy/9dbT+Fw= +github.com/hashicorp/go-sockaddr v1.0.7/go.mod h1:FZQbEYa1pxkQ7WLpyXJ6cbjpT8q0YgQaK/JakXqGyWw= 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= @@ -1388,6 +1491,8 @@ github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uG 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/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/hcl v1.0.1-vault-7 h1:ag5OxFVy3QYTFTJODRzTKVZ6xvdfLLCA1cy/Y6xGI0I= +github.com/hashicorp/hcl v1.0.1-vault-7/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= github.com/hashicorp/hcl/v2 v2.24.0 h1:2QJdZ454DSsYGoaE6QheQZjtKZSUs9Nh2izTWiwQxvE= github.com/hashicorp/hcl/v2 v2.24.0/go.mod h1:oGoO1FIQYfn/AgyOhlg9qLC6/nOJPX3qGbkZpYAcqfM= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= @@ -1397,6 +1502,11 @@ github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOn github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +github.com/hashicorp/vault/api v1.22.0 h1:+HYFquE35/B74fHoIeXlZIP2YADVboaPjaSicHEZiH0= +github.com/hashicorp/vault/api v1.22.0/go.mod h1:IUZA2cDvr4Ok3+NtK2Oq/r+lJeXkeCrHRmqdyWfpmGM= +github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef h1:A9HsByNhogrvm9cWb28sjiS3i7tcKCkflWFEkHfuAgM= +github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= @@ -1408,11 +1518,21 @@ github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1: github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw= github.com/iceber/iouring-go v0.0.0-20230403020409-002cfd2e2a90 h1:xrtfZokN++5kencK33hn2Kx3Uj8tGnjMEhdt6FMvHD0= github.com/iceber/iouring-go v0.0.0-20230403020409-002cfd2e2a90/go.mod h1:LEzdaZarZ5aqROlLIwJ4P7h3+4o71008fSy6wpaEB+s= +github.com/in-toto/attestation v1.1.2 h1:MBFn6lsMq6dptQZJBhalXTcWMb/aJy3V+GX3VYj/V1E= +github.com/in-toto/attestation v1.1.2/go.mod h1:gYFddHMZj3DiQ0b62ltNi1Vj5rC879bTmBbrv9CRHpM= github.com/in-toto/in-toto-golang v0.9.0 h1:tHny7ac4KgtsfrG6ybU8gVOZux2H8jN05AXJ9EBM1XU= github.com/in-toto/in-toto-golang v0.9.0/go.mod h1:xsBVrVsHNsB61++S6Dy2vWosKhuA3lUTQd+eF9HdeMo= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.7.5 h1:JHGfMnQY+IEtGM63d+NGMjoRpysB2JBwDr5fsngwmJs= +github.com/jackc/pgx/v5 v5.7.5/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= @@ -1427,16 +1547,22 @@ github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh6 github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 h1:TMtDYDHKYY15rFihtRfck/bfFqNfvcabqvXAFQfAUpY= +github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267/go.mod h1:h1nSAbGFqGVzn6Jyl1R/iCcBUHN4g+gW1u9CoBTrb9E= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= +github.com/jellydator/ttlcache/v3 v3.4.0 h1:YS4P125qQS0tNhtL6aeYkheEaB/m8HCqdMMP4mnWdTY= +github.com/jellydator/ttlcache/v3 v3.4.0/go.mod h1:Hw9EgjymziQD3yGsQdf1FqFdpp7YjFMd4Srg5EJlgD4= github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= -github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 h1:liMMTbpW34dhU4az1GN0pTPADwNmvoRSeoZ6PItiqnY= +github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/jmhodges/clock v1.2.0 h1:eq4kys+NI0PLngzaHEe7AmPT90XMGIEySD1JfV1PDIs= +github.com/jmhodges/clock v1.2.0/go.mod h1:qKjhA7x7u/lQpPB1XAqX1b1lCI/w3/fNuYpI/ZjLynI= github.com/joncrlsn/dque v0.0.0-20241024143830-7723fd131a64 h1:fmH2K7R8pZJ0wVvJyGFmDnECuAE3NLjfAoJkN9mtfc8= github.com/joncrlsn/dque v0.0.0-20241024143830-7723fd131a64/go.mod h1:dNKs71rs2VJGBAmttu7fouEsRQlRjxy0p1Sx+T5wbpY= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= @@ -1477,8 +1603,8 @@ github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= -github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co= -github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0= +github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= +github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= @@ -1510,6 +1636,8 @@ github.com/kubescape/workerpool v0.0.0-20250526074519-0e4a4e7f44cf/go.mod h1:Il5 github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs= +github.com/letsencrypt/boulder v0.20251110.0 h1:J8MnKICeilO91dyQ2n5eBbab24neHzUpYMUIOdOtbjc= +github.com/letsencrypt/boulder v0.20251110.0/go.mod h1:ogKCJQwll82m7OVHWyTuf8eeFCjuzdRQlgnZcCl0V+8= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= @@ -1528,8 +1656,6 @@ github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8S github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= -github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/matthyx/inspektor-gadget v0.0.0-20260226175242-c524fbad47d9 h1:5SElOPiaA2SKDGnLiWqocww+YagkLL9FPBBeMzKNTIg= github.com/matthyx/inspektor-gadget v0.0.0-20260226175242-c524fbad47d9/go.mod h1:V4TgEmWo37K72pQvC7XuRQssysrxIIkrNX4TtEkgiE0= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -1599,8 +1725,8 @@ github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTS 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.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -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/mapstructure v1.5.1-0.20231216201459-8508981c8b6c h1:cqn374mizHuIWj+OSJCajGr/phAmuMug9qIX3l9CflE= +github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 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= @@ -1650,6 +1776,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/natefinch/atomic v1.0.1 h1:ZPYKxkqQOx3KZ+RsbnP/YsgvxWQPGxjC0oBt2AhwV0A= +github.com/natefinch/atomic v1.0.1/go.mod h1:N/D/ELrljoqDyT3rZrsUmtsuzvHkeB/wWjHV22AZRbM= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/ncw/directio v1.0.5 h1:JSUBhdjEvVaJvOoyPAbcW0fnd0tvRXD76wEfZ1KcQz4= @@ -1667,27 +1795,44 @@ github.com/notaryproject/notation-plugin-framework-go v1.0.0 h1:6Qzr7DGXoCgXEQN+ github.com/notaryproject/notation-plugin-framework-go v1.0.0/go.mod h1:RqWSrTOtEASCrGOEffq0n8pSg2KOgKYiWqFWczRSics= github.com/notaryproject/tspclient-go v1.0.0 h1:AwQ4x0gX8IHnyiZB1tggpn5NFqHpTEm1SDX8YNv4Dg4= github.com/notaryproject/tspclient-go v1.0.0/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= +github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 h1:Up6+btDp321ZG5/zdSLo48H9Iaq0UQGthrhWC6pCxzE= +github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481/go.mod h1:yKZQO8QE2bHlgozqWDiRVqTFlLQSj30K/6SAK8EeYFw= github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249 h1:NHrXEjTNQY7P0Zfx1aMrNhpgxHmow66XQtm0aQLY0AE= github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249/go.mod h1:mpRZBD8SJ55OIICQ3iWH0Yz3cjzA61JdqMLoWXeB2+8= github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9lEc= github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= github.com/nwaples/rardecode/v2 v2.1.1 h1:OJaYalXdliBUXPmC8CZGQ7oZDxzX1/5mQmgn0/GASew= github.com/nwaples/rardecode/v2 v2.1.1/go.mod h1:7uz379lSxPe6j9nvzxUZ+n7mnJNgjsRNb6IbvGVHRmw= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= +github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/oleiade/lane/v2 v2.0.0 h1:XW/ex/Inr+bPkLd3O240xrFOhUkTd4Wy176+Gv0E3Qw= github.com/oleiade/lane/v2 v2.0.0/go.mod h1:i5FBPFAYSWCgLh58UkUGCChjcCzef/MI7PlQm2TKCeg= +github.com/oleiade/reflections v1.1.0 h1:D+I/UsXQB4esMathlt0kkZRJZdUDmhv5zGi/HOwYTWo= +github.com/oleiade/reflections v1.1.0/go.mod h1:mCxx0QseeVCHs5Um5HhJeCKVC7AwS8kO67tky4rdisA= github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM= github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y= github.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI= github.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g= -github.com/olekukonko/tablewriter v1.0.9 h1:XGwRsYLC2bY7bNd93Dk51bcPZksWZmLYuaTHR0FqfL8= -github.com/olekukonko/tablewriter v1.0.9/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo= +github.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY= +github.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo= github.com/olvrng/ujson v1.1.0 h1:8xVUzVlqwdMVWh5d1UHBtLQ1D50nxoPuPEq9Wozs8oA= github.com/olvrng/ujson v1.1.0/go.mod h1:Mz4G3RODTUfbkKyvi0lgmPx/7vd3Saksk+1jgk8s9xo= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.27.2 h1:LzwLj0b89qtIy6SSASkzlNvX6WktqurSHwkk2ipF/Ns= github.com/onsi/ginkgo/v2 v2.27.2/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A= github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k= github.com/opcoder0/capabilities v0.0.0-20221222060822-17fd73bffd2a h1:sbMMqulR2c6d2aeqOg5kzWv87unK0O4V78Dl1+YG4ys= @@ -1704,8 +1849,6 @@ github.com/opencontainers/runtime-tools v0.9.1-0.20250523060157-0ea5ed0382a2 h1: github.com/opencontainers/runtime-tools v0.9.1-0.20250523060157-0ea5ed0382a2/go.mod h1:MXdPzqAA8pHC58USHqNCSjyLnRQ6D+NjbpP+02Z1U/0= github.com/opencontainers/selinux v1.13.1 h1:A8nNeceYngH9Ow++M+VVEwJVpdFmrlxsN22F+ISDCJE= github.com/opencontainers/selinux v1.13.1/go.mod h1:S10WXZ/osk2kWOYKy1x2f/eXF5ZHJoUs8UU/2caNRbg= -github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A= -github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= github.com/packetcap/go-pcap v0.0.0-20250723190045-d00b185f30b7 h1:MfXxQU9tEe3zmyLVVwE8gJwQVtsG2aqzBkFNz0N6eAo= @@ -1716,6 +1859,8 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/indent v1.2.1 h1:lFiviAbISHv3Rf0jcuh489bi06hj98JsVMtIDZQb9yM= github.com/pborman/indent v1.2.1/go.mod h1:FitS+t35kIYtB5xWTZAPhnmrxcciEEOdbyrrpz5K6Vw= +github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw= +github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= @@ -1736,6 +1881,8 @@ github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pjbgf/sha1cd v0.4.0 h1:NXzbL1RvjTUi6kgYZCX3fPwwl27Q1LJndxtUDVfJGRY= github.com/pjbgf/sha1cd v0.4.0/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -1772,16 +1919,16 @@ github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvM github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= -github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4= +github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 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.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= -github.com/puzpuzpuz/xsync/v2 v2.4.1 h1:aGdE1C/HaR/QC6YAFdtZXi60Df8/qBIrs8PKrzkItcM= -github.com/puzpuzpuz/xsync/v2 v2.4.1/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU= +github.com/puzpuzpuz/xsync/v2 v2.5.1 h1:mVGYAvzDSu52+zaGyNjC+24Xw2bQi3kTr4QJ6N9pIIU= +github.com/puzpuzpuz/xsync/v2 v2.5.1/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= @@ -1802,6 +1949,8 @@ github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfF github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/s3rj1k/go-fanotify/fanotify v0.0.0-20240229202106-bca3154da60a h1:4VFls9SuqkqeioVevnaeTXrYKQ7JiEsxqKHfxp+/ovA= github.com/s3rj1k/go-fanotify/fanotify v0.0.0-20240229202106-bca3154da60a/go.mod h1:2zG1g57bc+D6FpNc68gsRXJgkidteqTMhWiiUP3m8UE= github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= @@ -1817,6 +1966,10 @@ github.com/sasha-s/go-deadlock v0.3.5 h1:tNCOEEDG6tBqrNDOX35j/7hL5FcFViG6awUGROb github.com/sasha-s/go-deadlock v0.3.5/go.mod h1:bugP6EGbdGYObIlx7pUZtWqlvo8k9H6vCBBsiChJQ5U= github.com/sassoftware/go-rpmutils v0.4.0 h1:ojND82NYBxgwrV+mX1CWsd5QJvvEZTKddtCdFLPWhpg= github.com/sassoftware/go-rpmutils v0.4.0/go.mod h1:3goNWi7PGAT3/dlql2lv3+MSN5jNYPjT5mVcQcIsYzI= +github.com/sassoftware/relic v7.2.1+incompatible h1:Pwyh1F3I0r4clFJXkSI8bOyJINGqpgjJU3DYAZeI05A= +github.com/sassoftware/relic v7.2.1+incompatible/go.mod h1:CWfAxv73/iLZ17rbyhIEq3K9hs5w6FpNMdUT//qR+zk= +github.com/sassoftware/relic/v7 v7.6.2 h1:rS44Lbv9G9eXsukknS4mSjIAuuX+lMq/FnStgmZlUv4= +github.com/sassoftware/relic/v7 v7.6.2/go.mod h1:kjmP0IBVkJZ6gXeAu35/KCEfca//+PKM6vTAsyDPY+k= github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e h1:7q6NSFZDeGfvvtIRwBrU/aegEYJYmvev0cHAwo17zZQ= github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e/go.mod h1:DkpGd78rljTxKAnTDPFqXSGxvETQnJyuSOQwsHycqfs= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= @@ -1824,8 +1977,8 @@ github.com/sebdah/goldie/v2 v2.7.1 h1:PkBHymaYdtvEkZV7TmyqKxdmn5/Vcj+8TpATWZjnG5 github.com/sebdah/goldie/v2 v2.7.1/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI= github.com/seccomp/libseccomp-golang v0.11.0 h1:SDkcBRqGLP+sezmMACkxO1EfgbghxIxnRKfd6mHUEis= github.com/seccomp/libseccomp-golang v0.11.0/go.mod h1:5m1Lk8E9OwgZTTVz4bBOer7JuazaBa+xTkM895tDiWc= -github.com/secure-systems-lab/go-securesystemslib v0.9.1 h1:nZZaNz4DiERIQguNy0cL5qTdn9lR8XKHf4RUyG1Sx3g= -github.com/secure-systems-lab/go-securesystemslib v0.9.1/go.mod h1:np53YzT0zXGMv6x4iEWc9Z59uR+x+ndLwCLqPYpLXVU= +github.com/secure-systems-lab/go-securesystemslib v0.10.0 h1:l+H5ErcW0PAehBNrBxoGv1jjNpGYdZ9RcheFkB2WI14= +github.com/secure-systems-lab/go-securesystemslib v0.10.0/go.mod h1:MRKONWmRoFzPNQ9USRF9i1mc7MvAVvF1LlW8X5VWDvk= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= @@ -1857,15 +2010,35 @@ github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1l github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= +github.com/sigstore/cosign/v3 v3.0.5 h1:c1zPqjU+H4wmirgysC+AkWMg7a7fykyOYF/m+F1150I= +github.com/sigstore/cosign/v3 v3.0.5/go.mod h1:ble1vMvJagCFyTIDkibCq6MIHiWDw00JNYl0f9rB4T4= +github.com/sigstore/fulcio v1.8.5 h1:HYTD1/L5wlBp8JxsWxUf8hmfaNBBF/x3r3p5l6tZwbA= +github.com/sigstore/fulcio v1.8.5/go.mod h1:tSLYK3JsKvJpDW1BsIsVHZgHj+f8TjXARzqIUWSsSPQ= github.com/sigstore/protobuf-specs v0.5.0 h1:F8YTI65xOHw70NrvPwJ5PhAzsvTnuJMGLkA4FIkofAY= github.com/sigstore/protobuf-specs v0.5.0/go.mod h1:+gXR+38nIa2oEupqDdzg4qSBT0Os+sP7oYv6alWewWc= +github.com/sigstore/rekor v1.5.0 h1:rL7SghHd5HLCtsCrxw0yQg+NczGvM75EjSPPWuGjaiQ= +github.com/sigstore/rekor v1.5.0/go.mod h1:D7JoVCUkxwQOpPDNYeu+CE8zeBC18Y5uDo6tF8s2rcQ= +github.com/sigstore/rekor-tiles/v2 v2.2.0 h1:QwJNwxT+k5A3id+Hrg+8vYcNsTaB0Sj51xjfW2rKyAs= +github.com/sigstore/rekor-tiles/v2 v2.2.0/go.mod h1:/WNRYctHKdxcjgXydYwO5OclW72Zqh6fNHSyGE8zQOE= github.com/sigstore/sigstore v1.10.4 h1:ytOmxMgLdcUed3w1SbbZOgcxqwMG61lh1TmZLN+WeZE= github.com/sigstore/sigstore v1.10.4/go.mod h1:tDiyrdOref3q6qJxm2G+JHghqfmvifB7hw+EReAfnbI= +github.com/sigstore/sigstore-go v1.1.4 h1:wTTsgCHOfqiEzVyBYA6mDczGtBkN7cM8mPpjJj5QvMg= +github.com/sigstore/sigstore-go v1.1.4/go.mod h1:2U/mQOT9cjjxrtIUeKDVhL+sHBKsnWddn8URlswdBsg= +github.com/sigstore/sigstore/pkg/signature/kms/aws v1.10.4 h1:VZ+L6SKVWbLPHznIF0tBuO7qKMFdJiJMVwFKu9DlY5o= +github.com/sigstore/sigstore/pkg/signature/kms/aws v1.10.4/go.mod h1:Rstj47WpJym25il8j4jTL0BfikzP/9AhVD+DsBcYzZc= +github.com/sigstore/sigstore/pkg/signature/kms/azure v1.10.4 h1:G7yOv8bxk3zIEEZyVCixPxtePIAm+t3ZWSaKRPzVw+o= +github.com/sigstore/sigstore/pkg/signature/kms/azure v1.10.4/go.mod h1:hxJelB/bRItMYOzi6qD9xEKjse2QZcikh4TbysfdDHc= +github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.10.4 h1:Qxt6dE4IwhJ6gIXmg2q4S/SeqEDSZ29nmfsv7Zb6LL4= +github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.10.4/go.mod h1:hJVeNOwarqfyALjOwsf0OR8YA/A96NABucEaQumPr30= +github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.10.4 h1:KVavYMPfSf5NryOl6VrZ9nRG3fXOOJOPp7Czk/YCPkM= +github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.10.4/go.mod h1:J7CA1AaBkyK8dYq6EdQANhj+8oEcsA7PrIp088qgPiY= +github.com/sigstore/timestamp-authority/v2 v2.0.4 h1:65IBa4LUeFWDQu9hiTt5lBpi/F5jonJWZtH6VLn4InU= +github.com/sigstore/timestamp-authority/v2 v2.0.4/go.mod h1:EXJLiMDBqRPlzC02hPiFSiYTCqSuUpU68a4vr0DFePM= 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.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af h1:Sp5TG9f7K39yfB+If0vjp97vuT74F72r8hfRpP8jLU0= -github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= +github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8= github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY= github.com/sorairolake/lzip-go v0.3.7 h1:vP2uiD/NoklLyzYMdgOWkZME0ulkSfVTTE4MNRKCwNs= @@ -1916,6 +2089,7 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 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.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.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= @@ -1932,11 +2106,31 @@ github.com/sylabs/sif/v2 v2.22.0 h1:Y+xXufp4RdgZe02SR3nWEg7S6q4tPWN237WHYzkDSKA= github.com/sylabs/sif/v2 v2.22.0/go.mod h1:W1XhWTmG1KcG7j5a3KSYdMcUIFvbs240w/MMVW627hs= github.com/sylabs/squashfs v1.0.6 h1:PvJcDzxr+vIm2kH56mEMbaOzvGu79gK7P7IX+R7BDZI= github.com/sylabs/squashfs v1.0.6/go.mod h1:DlDeUawVXLWAsSRa085Eo0ZenGzAB32JdAUFaB0LZfE= +github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= +github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/terminalstatic/go-xsd-validate v0.1.6 h1:TenYeQ3eY631qNi1/cTmLH/s2slHPRKTTHT+XSHkepo= github.com/terminalstatic/go-xsd-validate v0.1.6/go.mod h1:18lsvYFofBflqCrvo1umpABZ99+GneNTw2kEEc8UPJw= github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw= github.com/therootcompany/xz v1.0.1/go.mod h1:3K3UH1yCKgBneZYhuQUvJ9HPD19UEXEI0BWbMn8qNMY= +github.com/theupdateframework/go-tuf v0.7.0 h1:CqbQFrWo1ae3/I0UCblSbczevCCbS31Qvs5LdxRWqRI= +github.com/theupdateframework/go-tuf v0.7.0/go.mod h1:uEB7WSY+7ZIugK6R1hiBMBjQftaFzn7ZCDJcp1tCUug= +github.com/theupdateframework/go-tuf/v2 v2.4.1 h1:K6ewW064rKZCPkRo1W/CTbTtm/+IB4+coG1iNURAGCw= +github.com/theupdateframework/go-tuf/v2 v2.4.1/go.mod h1:Nex2enPVYDFCklrnbTzl3OVwD7fgIAj0J5++z/rvCj8= +github.com/tink-crypto/tink-go-awskms/v2 v2.1.0 h1:N9UxlsOzu5mttdjhxkDLbzwtEecuXmlxZVo/ds7JKJI= +github.com/tink-crypto/tink-go-awskms/v2 v2.1.0/go.mod h1:PxSp9GlOkKL9rlybW804uspnHuO9nbD98V/fDX4uSis= +github.com/tink-crypto/tink-go-gcpkms/v2 v2.2.0 h1:3B9i6XBXNTRspfkTC0asN5W0K6GhOSgcujNiECNRNb0= +github.com/tink-crypto/tink-go-gcpkms/v2 v2.2.0/go.mod h1:jY5YN2BqD/KSCHM9SqZPIpJNG/u3zwfLXHgws4x2IRw= +github.com/tink-crypto/tink-go-hcvault/v2 v2.4.0 h1:j+S+WKBQ5ya26A5EM/uXoVe+a2IaPQN8KgBJZ22cJ+4= +github.com/tink-crypto/tink-go-hcvault/v2 v2.4.0/go.mod h1:OCKJIujnTzDq7f+73NhVs99oA2c1TR6nsOpuasYM6Yo= +github.com/tink-crypto/tink-go/v2 v2.6.0 h1:+KHNBHhWH33Vn+igZWcsgdEPUxKwBMEe0QC60t388v4= +github.com/tink-crypto/tink-go/v2 v2.6.0/go.mod h1:2WbBA6pfNsAfBwDCggboaHeB2X29wkU8XHtGwh2YIk8= +github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0= +github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs= +github.com/transparency-dev/formats v0.0.0-20251017110053-404c0d5b696c h1:5a2XDQ2LiAUV+/RjckMyq9sXudfrPSuCY4FuPC1NyAw= +github.com/transparency-dev/formats v0.0.0-20251017110053-404c0d5b696c/go.mod h1:g85IafeFJZLxlzZCDRu4JLpfS7HKzR+Hw9qRh3bVzDI= +github.com/transparency-dev/merkle v0.0.2 h1:Q9nBoQcZcgPamMkGn7ghV8XiTZ/kRxn1yCG81+twTK4= +github.com/transparency-dev/merkle v0.0.2/go.mod h1:pqSy+OXefQ1EDUVmAJ8MUhHB9TXGuzVAT58PqBoHz1A= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= @@ -1988,6 +2182,16 @@ github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZ github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+SevawU= github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g= +github.com/ysmood/fetchup v0.2.3 h1:ulX+SonA0Vma5zUFXtv52Kzip/xe7aj4vqT5AJwQ+ZQ= +github.com/ysmood/fetchup v0.2.3/go.mod h1:xhibcRKziSvol0H1/pj33dnKrYyI2ebIvz5cOOkYGns= +github.com/ysmood/goob v0.4.0 h1:HsxXhyLBeGzWXnqVKtmT9qM7EuVs/XOgkX7T6r1o1AQ= +github.com/ysmood/goob v0.4.0/go.mod h1:u6yx7ZhS4Exf2MwciFr6nIM8knHQIE22lFpWHnfql18= +github.com/ysmood/got v0.40.0 h1:ZQk1B55zIvS7zflRrkGfPDrPG3d7+JOza1ZkNxcc74Q= +github.com/ysmood/got v0.40.0/go.mod h1:W7DdpuX6skL3NszLmAsC5hT7JAhuLZhByVzHTq874Qg= +github.com/ysmood/gson v0.7.3 h1:QFkWbTH8MxyUTKPkVWAENJhxqdBa4lYTQWqZCiLG6kE= +github.com/ysmood/gson v0.7.3/go.mod h1:3Kzs5zDl21g5F/BlLTNcuAGAYLKt2lV5G8D1zF3RNmg= +github.com/ysmood/leakless v0.9.0 h1:qxCG5VirSBvmi3uynXFkcnLMzkphdh3xx5FtrORwDCU= +github.com/ysmood/leakless v0.9.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -1995,6 +2199,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zalando/go-keyring v0.2.3 h1:v9CUu9phlABObO4LPWycf+zwMG7nlbb3t/B5wa97yms= +github.com/zalando/go-keyring v0.2.3/go.mod h1:HL4k+OXQfJUWaMnqyuSOc0drfGPX2b51Du6K+MRgZMk= github.com/zclconf/go-cty v1.16.3 h1:osr++gw2T61A8KVYHoQiFbFd1Lh3JOCXc/jFLJXKTxk= github.com/zclconf/go-cty v1.16.3/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo= @@ -2004,8 +2210,8 @@ github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaD go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= -go.mongodb.org/mongo-driver v1.17.4 h1:jUorfmVzljjr0FLzYQsGP8cgN/qzzxlY9Vh0C9KFXVw= -go.mongodb.org/mongo-driver v1.17.4/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= +go.mongodb.org/mongo-driver v1.17.6 h1:87JUG1wZfWsr6rIz3ZmpH90rL5tea7O3IHuSwHUpsss= +go.mongodb.org/mongo-driver v1.17.6/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= @@ -2020,8 +2226,8 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/detectors/gcp v1.38.0 h1:ZoYbqX7OaA/TAikspPl3ozPI6iY6LiIY9I8cUfm+pJs= go.opentelemetry.io/contrib/detectors/gcp v1.38.0/go.mod h1:SU+iU7nu5ud4oCb3LQOhIZ3nRLj6FNVrKgtflbaf2ts= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0 h1:rbRJ8BBoVMsQShESYZ0FkvcITu8X8QNwJogcLUmDNNw= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0/go.mod h1:ru6KHrNtNHxM4nD/vd6QrLVWgKhxPYgblq4VAtNawTQ= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg= go.opentelemetry.io/contrib/instrumentation/runtime v0.64.0 h1:/+/+UjlXjFcdDlXxKL1PouzX8Z2Vl0OxolRKeBEgYDw= @@ -2032,12 +2238,12 @@ go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 h1:QQqYw3lkr go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0/go.mod h1:gSVQcr17jk2ig4jqJ2DX30IdWH251JcNAecvrqTxH1s= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 h1:Oe2z/BCg5q7k4iXC3cqJxKYg0ieRiOqF0cecFYdPTwk= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0/go.mod h1:ZQM5lAJpOsKnYagGg/zV2krVqTtaVdYdDkhMoX6Oalg= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 h1:rixTyDGXFxRy1xzhKrotaHy3/KXdPhlWARrCgK+eqUY= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0/go.mod h1:dowW6UsM9MKbJq5JTz2AMVp3/5iW5I/TStsk8S+CfHw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 h1:Ckwye2FpXkYgiHX7fyVrN1uA/UYd9ounqqTuSNAv0k4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0/go.mod h1:teIFJh5pW2y+AN7riv6IBPX2DuesS3HgP39mwOspKwU= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 h1:wm/Q0GAAykXv83wzcKzGGqAnnfLFyFe7RslekZuv+VI= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0/go.mod h1:ra3Pa40+oKjvYh+ZD3EdxFZZB0xdMfuileHAm4nNN7w= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7iZeKJdeB8/NYHrJ48fdGc71Llo5bJ1J4DWUE= go.opentelemetry.io/otel/log v0.15.0 h1:0VqVnc3MgyYd7QqNVIldC3dsLFKgazR6P3P3+ypkyDY= @@ -2059,6 +2265,8 @@ go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= +go.step.sm/crypto v0.76.0 h1:K23BSaeoiY7Y5dvvijTeYC9EduDBetNwQYMBwMhi1aA= +go.step.sm/crypto v0.76.0/go.mod h1:PXYJdKkK8s+GHLwLguFaLxHNAFsFL3tL1vSBrYfey5k= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= @@ -2066,8 +2274,8 @@ go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9i go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= -go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= +go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= @@ -2100,8 +2308,8 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= -golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= -golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= +golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= +golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -2117,8 +2325,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= -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/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2wtOnGAHZWCHUM4KGzY= +golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -2167,8 +2375,8 @@ golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= -golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= +golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= +golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= 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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -2201,6 +2409,7 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= @@ -2217,6 +2426,7 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= 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-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -2249,8 +2459,8 @@ 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.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= -golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= -golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= +golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -2283,8 +2493,8 @@ golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= -golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= -golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ= +golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= 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= @@ -2328,11 +2538,14 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/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-20191001151750-bb3f8db39f24/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-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -2360,6 +2573,7 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -2412,6 +2626,7 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc 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.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -2442,8 +2657,8 @@ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= -golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= -golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= +golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= +golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -2464,8 +2679,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 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.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= -golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= +golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -2527,6 +2742,7 @@ golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -2543,8 +2759,8 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= 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= @@ -2629,8 +2845,8 @@ google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/ google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0= google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= -google.golang.org/api v0.242.0 h1:7Lnb1nfnpvbkCiZek6IXKdJ0MFuAZNAJKQfA1ws62xg= -google.golang.org/api v0.242.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50= +google.golang.org/api v0.267.0 h1:w+vfWPMPYeRs8qH1aYYsFX68jMls5acWl/jocfLomwE= +google.golang.org/api v0.267.0/go.mod h1:Jzc0+ZfLnyvXma3UtaTl023TdhZu6OMBP9tJ+0EmFD0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -2780,12 +2996,12 @@ google.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOl google.golang.org/genproto v0.0.0-20230330154414-c0448cd141ea/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= -google.golang.org/genproto v0.0.0-20250715232539-7130f93afb79 h1:Nt6z9UHqSlIdIGJdz6KhTIs2VRx/iOsA5iE8bmQNcxs= -google.golang.org/genproto v0.0.0-20250715232539-7130f93afb79/go.mod h1:kTmlBHMPqR5uCZPBvwa2B18mvubkjyY3CRLI0c6fj0s= -google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 h1:fCvbg86sFXwdrl5LgVcTEvNC+2txB5mgROGmRL5mrls= -google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto v0.0.0-20260128011058-8636f8732409 h1:VQZ/yAbAtjkHgH80teYd2em3xtIkkHd7ZhqfH2N9CsM= +google.golang.org/genproto v0.0.0-20260128011058-8636f8732409/go.mod h1:rxKD3IEILWEu3P44seeNOAwZN4SaoKaQ/2eTg4mM6EM= +google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 h1:merA0rdPeUV3YIIfHHcH4qBkiQAc1nfCKSI7lB4cV2M= +google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409/go.mod h1:fl8J1IvUjCilwZzQowmw2b7HQB2eAuYBabMXzWurF+I= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20 h1:Jr5R2J6F6qWyzINc+4AM8t5pfUz6beZpHp678GNrMbE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= @@ -2830,8 +3046,8 @@ google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5v google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= -google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= -google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= +google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc= +google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= 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= @@ -2864,11 +3080,14 @@ gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qS gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mcuadros/go-syslog.v2 v2.3.0 h1:kcsiS+WsTKyIEPABJBJtoG0KkOS6yzvJ+/eZlhD79kk= gopkg.in/mcuadros/go-syslog.v2 v2.3.0/go.mod h1:l5LPIyOOyIdQquNg+oU6Z3524YwrcqEm0aKH+5zpt2U= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -2877,14 +3096,15 @@ 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 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 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.0 h1:Ljk6PdHdOhAb5aDMWXjDLMMhph+BpztA4v1QdqEW2eY= -gotest.tools/v3 v3.5.0/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= +gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= +gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -2897,18 +3117,18 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= istio.io/pkg v0.0.0-20231221211216-7635388a563e h1:ZlLVbKDlCzfP0MPbWc6VRcY23d9NdjLxwpPQpDrh3Gc= istio.io/pkg v0.0.0-20231221211216-7635388a563e/go.mod h1:fvmqEdHhZjYYwf6dSiIwvwc7db54kMWVTfsb91KmhzY= -k8s.io/api v0.35.0 h1:iBAU5LTyBI9vw3L5glmat1njFK34srdLmktWwLTprlY= -k8s.io/api v0.35.0/go.mod h1:AQ0SNTzm4ZAczM03QH42c7l3bih1TbAXYo0DkF8ktnA= +k8s.io/api v0.35.1 h1:0PO/1FhlK/EQNVK5+txc4FuhQibV25VLSdLMmGpDE/Q= +k8s.io/api v0.35.1/go.mod h1:28uR9xlXWml9eT0uaGo6y71xK86JBELShLy4wR1XtxM= k8s.io/apiextensions-apiserver v0.35.0 h1:3xHk2rTOdWXXJM+RDQZJvdx0yEOgC0FgQ1PlJatA5T4= k8s.io/apiextensions-apiserver v0.35.0/go.mod h1:E1Ahk9SADaLQ4qtzYFkwUqusXTcaV2uw3l14aqpL2LU= -k8s.io/apimachinery v0.35.0 h1:Z2L3IHvPVv/MJ7xRxHEtk6GoJElaAqDCCU0S6ncYok8= -k8s.io/apimachinery v0.35.0/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns= +k8s.io/apimachinery v0.35.1 h1:yxO6gV555P1YV0SANtnTjXYfiivaTPvCTKX6w6qdDsU= +k8s.io/apimachinery v0.35.1/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns= k8s.io/apiserver v0.35.0 h1:CUGo5o+7hW9GcAEF3x3usT3fX4f9r8xmgQeCBDaOgX4= k8s.io/apiserver v0.35.0/go.mod h1:QUy1U4+PrzbJaM3XGu2tQ7U9A4udRRo5cyxkFX0GEds= k8s.io/cli-runtime v0.35.0 h1:PEJtYS/Zr4p20PfZSLCbY6YvaoLrfByd6THQzPworUE= k8s.io/cli-runtime v0.35.0/go.mod h1:VBRvHzosVAoVdP3XwUQn1Oqkvaa8facnokNkD7jOTMY= -k8s.io/client-go v0.35.0 h1:IAW0ifFbfQQwQmga0UdoH0yvdqrbwMdq9vIFEhRpxBE= -k8s.io/client-go v0.35.0/go.mod h1:q2E5AAyqcbeLGPdoRB+Nxe3KYTfPce1Dnu1myQdqz9o= +k8s.io/client-go v0.35.1 h1:+eSfZHwuo/I19PaSxqumjqZ9l5XiTEKbIaJ+j1wLcLM= +k8s.io/client-go v0.35.1/go.mod h1:1p1KxDt3a0ruRfc/pG4qT/3oHmUj1AhSHEcxNSGg+OA= k8s.io/component-base v0.35.0 h1:+yBrOhzri2S1BVqyVSvcM3PtPyx5GUxCK2tinZz1G94= k8s.io/component-base v0.35.0/go.mod h1:85SCX4UCa6SCFt6p3IKAPej7jSnF3L8EbfSyMZayJR0= k8s.io/cri-api v0.35.0 h1:fxLSKyJHqbyCSUsg1rW4DRpmjSEM/elZ1GXzYTSLoDQ= @@ -2928,19 +3148,19 @@ lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= -modernc.org/cc/v4 v4.26.2 h1:991HMkLjJzYBIfha6ECZdjrIYz2/1ayr+FL8GN+CNzM= -modernc.org/cc/v4 v4.26.2/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= +modernc.org/cc/v4 v4.26.5 h1:xM3bX7Mve6G8K8b+T11ReenJOT+BmVqQj0FY5T4+5Y4= +modernc.org/cc/v4 v4.26.5/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws= modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo= -modernc.org/ccgo/v4 v4.28.0 h1:rjznn6WWehKq7dG4JtLRKxb52Ecv8OUGah8+Z/SfpNU= -modernc.org/ccgo/v4 v4.28.0/go.mod h1:JygV3+9AV6SmPhDasu4JgquwU81XAKLd3OKTUDNOiKE= +modernc.org/ccgo/v4 v4.28.1 h1:wPKYn5EC/mYTqBO373jKjvX2n+3+aK7+sICCv4Fjy1A= +modernc.org/ccgo/v4 v4.28.1/go.mod h1:uD+4RnfrVgE6ec9NGguUNdhqzNIeeomeXf6CL0GTE5Q= modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= -modernc.org/fileutil v1.3.8 h1:qtzNm7ED75pd1C7WgAGcK4edm4fvhtBsEiI/0NQ54YM= -modernc.org/fileutil v1.3.8/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc= +modernc.org/fileutil v1.3.40 h1:ZGMswMNc9JOCrcrakF1HrvmergNLAmxOPjizirpfqBA= +modernc.org/fileutil v1.3.40/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc= modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= @@ -2953,8 +3173,8 @@ modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0= modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s= -modernc.org/libc v1.66.3 h1:cfCbjTUcdsKyyZZfEUKfoHcP3S0Wkvz3jgSzByEWVCQ= -modernc.org/libc v1.66.3/go.mod h1:XD9zO8kt59cANKvHPXpx7yS2ELPheAey0vjIuZOhOU8= +modernc.org/libc v1.66.10 h1:yZkb3YeLx4oynyR+iUsXsybsX4Ubx7MQlSYEw4yj59A= +modernc.org/libc v1.66.10/go.mod h1:8vGSEwvoUoltr4dlywvHqjtAqHBaw0j1jI7iFBTAr2I= modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= @@ -2972,8 +3192,8 @@ modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= -modernc.org/sqlite v1.38.2 h1:Aclu7+tgjgcQVShZqim41Bbw9Cho0y/7WzYptXqkEek= -modernc.org/sqlite v1.38.2/go.mod h1:cPTJYSlgg3Sfg046yBShXENNtPrWrDX8bsbAQBzgQ5E= +modernc.org/sqlite v1.40.1 h1:VfuXcxcUWWKRBuP8+BR9L7VnmusMgBNNnBYGEe9w/iY= +modernc.org/sqlite v1.40.1/go.mod h1:9fjQZ0mB1LLP0GYrp39oOJXx/I2sxEnZtzCmEQIKvGE= modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= @@ -3005,6 +3225,8 @@ sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099Yo sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= +software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k= +software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= zombiezen.com/go/sqlite v1.4.0 h1:N1s3RIljwtp4541Y8rM880qgGIgq3fTD2yks1xftnKU= diff --git a/pkg/config/config.go b/pkg/config/config.go index 4049cec77..e21b095ef 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -66,6 +66,7 @@ type Config struct { EnableRuntimeDetection bool `mapstructure:"runtimeDetectionEnabled"` EnableSbomGeneration bool `mapstructure:"sbomGenerationEnabled"` EnableSeccomp bool `mapstructure:"seccompServiceEnabled"` + EnableSignatureVerification bool `mapstructure:"enableSignatureVerification"` HostMonitoringEnabled bool `mapstructure:"hostMonitoringEnabled"` StandaloneMonitoringEnabled bool `mapstructure:"standaloneMonitoringEnabled"` SeccompProfileBackend string `mapstructure:"seccompProfileBackend"` @@ -180,6 +181,7 @@ func LoadConfig(path string) (Config, error) { viper.SetDefault("celConfigCache::maxSize", 100000) viper.SetDefault("celConfigCache::ttl", 1*time.Minute) viper.SetDefault("ignoreRuleBindings", false) + viper.SetDefault("enableSignatureVerification", false) viper.SetDefault("dnsCacheSize", 50000) viper.SetDefault("seccompProfileBackend", "storage") // "storage" or "crd" @@ -212,6 +214,7 @@ func LoadConfig(path string) (Config, error) { viper.SetDefault("hostSensorInterval", 5*time.Minute) viper.AutomaticEnv() + _ = viper.BindEnv("enableSignatureVerification", "ENABLE_SIGNATURE_VERIFICATION") err := viper.ReadInConfig() if err != nil { diff --git a/pkg/objectcache/applicationprofilecache/applicationprofilecache.go b/pkg/objectcache/applicationprofilecache/applicationprofilecache.go index c159ee867..59686128c 100644 --- a/pkg/objectcache/applicationprofilecache/applicationprofilecache.go +++ b/pkg/objectcache/applicationprofilecache/applicationprofilecache.go @@ -2,6 +2,7 @@ package applicationprofilecache import ( "context" + "errors" "fmt" "strings" "sync" @@ -18,6 +19,8 @@ import ( "github.com/kubescape/node-agent/pkg/objectcache" "github.com/kubescape/node-agent/pkg/objectcache/applicationprofilecache/callstackcache" "github.com/kubescape/node-agent/pkg/resourcelocks" + "github.com/kubescape/node-agent/pkg/signature" + "github.com/kubescape/node-agent/pkg/signature/profiles" "github.com/kubescape/node-agent/pkg/storage" "github.com/kubescape/node-agent/pkg/utils" "github.com/kubescape/storage/pkg/apis/softwarecomposition/v1beta1" @@ -244,6 +247,12 @@ func (apc *ApplicationProfileCacheImpl) updateAllProfiles(ctx context.Context) { continue } + // Verify signature if enabled + if err := apc.verifyApplicationProfile(fullProfile, workloadID, "profile", true); err != nil { + // Continue to next profile as per requirements: skip on verification failure + continue + } + apc.workloadIDToProfile.Set(workloadID, fullProfile) logger.L().Debug("updated profile in cache", helpers.String("workloadID", workloadID), @@ -265,6 +274,52 @@ func (apc *ApplicationProfileCacheImpl) updateAllProfiles(ctx context.Context) { } } +// verifyApplicationProfile verifies the profile signature if verification is enabled. +// Returns error if verification fails, nil otherwise (including when verification is disabled). +// Also updates profileState with error details if verification fails. +func (apc *ApplicationProfileCacheImpl) verifyApplicationProfile(profile *v1beta1.ApplicationProfile, workloadID, context string, recordFailure bool) error { + if !apc.cfg.EnableSignatureVerification { + return nil + } + profileAdapter := profiles.NewApplicationProfileAdapter(profile) + if err := signature.VerifyObject(profileAdapter); err != nil { + // Only warn if signature exists but doesn't match; missing signatures are debug + if errors.Is(err, signature.ErrObjectNotSigned) { + logger.L().Debug(context+" is not signed, skipping", + helpers.String("profile", profile.Name), + helpers.String("namespace", profile.Namespace), + helpers.String("workloadID", workloadID)) + } else { + logger.L().Warning(context+" signature verification failed, skipping", + helpers.String("profile", profile.Name), + helpers.String("namespace", profile.Namespace), + helpers.String("workloadID", workloadID), + helpers.Error(err)) + } + + // Update profile state with verification error + if recordFailure { + apc.setVerificationFailed(workloadID, profile.Name, err) + } + + return err + } + logger.L().Debug(context+" verification successful", + helpers.String("profile", profile.Name), + helpers.String("namespace", profile.Namespace)) + return nil +} + +func (apc *ApplicationProfileCacheImpl) setVerificationFailed(workloadID, profileName string, err error) { + profileState := &objectcache.ProfileState{ + Completion: "failed", + Status: "verification-failed", + Name: profileName, + Error: err, + } + apc.workloadIDToProfileState.Set(workloadID, profileState) +} + // handleUserManagedProfile handles user-managed profiles func (apc *ApplicationProfileCacheImpl) handleUserManagedProfile(profile *v1beta1.ApplicationProfile) { normalizedProfileName := strings.TrimPrefix(profile.Name, helpersv1.UserApplicationProfilePrefix) @@ -314,6 +369,11 @@ func (apc *ApplicationProfileCacheImpl) handleUserManagedProfile(profile *v1beta return } + // Verify signature if enabled + if err := apc.verifyApplicationProfile(fullUserProfile, toMerge.wlid, "user-managed profile", false); err != nil { + return + } + // Merge the user-managed profile with the normal profile // First, pull the original profile from the storage @@ -533,6 +593,18 @@ func (apc *ApplicationProfileCacheImpl) addContainer(container *containercollect apc.workloadIDToProfileState.Set(workloadID, profileState) return nil } + + // Verify signature if enabled + if err := apc.verifyApplicationProfile(fullProfile, workloadID, "user-defined profile", false); err != nil { + // Update the profile state to indicate an error + profileState := &objectcache.ProfileState{ + Error: fmt.Errorf("signature verification failed: %w", err), + } + apc.workloadIDToProfileState.Set(workloadID, profileState) + // Skip caching the unverified profile + return nil + } + // Update the profile in the cache apc.workloadIDToProfile.Set(workloadID, fullProfile) logger.L().Debug("added user-defined profile to cache", diff --git a/pkg/objectcache/networkneighborhoodcache/networkneighborhoodcache.go b/pkg/objectcache/networkneighborhoodcache/networkneighborhoodcache.go index 254f6ae64..0ed61cf42 100644 --- a/pkg/objectcache/networkneighborhoodcache/networkneighborhoodcache.go +++ b/pkg/objectcache/networkneighborhoodcache/networkneighborhoodcache.go @@ -17,6 +17,8 @@ import ( "github.com/kubescape/node-agent/pkg/config" "github.com/kubescape/node-agent/pkg/objectcache" "github.com/kubescape/node-agent/pkg/resourcelocks" + "github.com/kubescape/node-agent/pkg/signature" + "github.com/kubescape/node-agent/pkg/signature/profiles" "github.com/kubescape/node-agent/pkg/storage" "github.com/kubescape/node-agent/pkg/utils" "github.com/kubescape/storage/pkg/apis/softwarecomposition/v1beta1" @@ -238,6 +240,21 @@ func (nnc *NetworkNeighborhoodCacheImpl) updateAllNetworkNeighborhoods(ctx conte continue } + // Verify signature if enabled + if nnc.cfg.EnableSignatureVerification { + adapter := profiles.NewNetworkNeighborhoodAdapter(fullNN) + if err := signature.VerifyObjectStrict(adapter); err != nil { + logger.L().Warning("network neighborhood signature verification failed, skipping", + helpers.String("workloadID", workloadID), + helpers.String("namespace", namespace), + helpers.String("name", fullNN.Name), + helpers.Error(err)) + profileState.Error = fmt.Errorf("signature verification failed: %w", err) + nnc.workloadIDToProfileState.Set(workloadID, profileState) + continue + } + } + nnc.workloadIDToNetworkNeighborhood.Set(workloadID, fullNN) logger.L().Debug("updated network neighborhood in cache", helpers.String("workloadID", workloadID), @@ -308,8 +325,62 @@ func (nnc *NetworkNeighborhoodCacheImpl) handleUserManagedNetworkNeighborhood(nn helpers.Error(err)) return } + + // Verify signature on the original network neighborhood before merging + if nnc.cfg.EnableSignatureVerification { + adapter := profiles.NewNetworkNeighborhoodAdapter(originalNN) + if err := signature.VerifyObjectStrict(adapter); err != nil { + logger.L().Warning("original network neighborhood signature verification failed, skipping merge", + helpers.String("workloadID", toMerge.wlid), + helpers.String("namespace", originalNN.Namespace), + helpers.String("name", originalNN.Name), + helpers.Error(err)) + profileState := &objectcache.ProfileState{ + Completion: originalNN.Annotations[helpersv1.CompletionMetadataKey], + Status: originalNN.Annotations[helpersv1.StatusMetadataKey], + Name: originalNN.Name, + Error: fmt.Errorf("signature verification failed: %w", err), + } + nnc.workloadIDToProfileState.Set(toMerge.wlid, profileState) + // Evict stale merged profile from cache on verification failure + nnc.workloadIDToNetworkNeighborhood.Delete(toMerge.wlid) + return + } + } + + // Verify signature on the user-managed network neighborhood before merging + if nnc.cfg.EnableSignatureVerification { + adapter := profiles.NewNetworkNeighborhoodAdapter(fullUserNN) + if err := signature.VerifyObjectStrict(adapter); err != nil { + logger.L().Warning("user-managed network neighborhood signature verification failed, skipping merge", + helpers.String("workloadID", toMerge.wlid), + helpers.String("namespace", fullUserNN.Namespace), + helpers.String("name", fullUserNN.Name), + helpers.Error(err)) + profileState := &objectcache.ProfileState{ + Completion: fullUserNN.Annotations[helpersv1.CompletionMetadataKey], + Status: fullUserNN.Annotations[helpersv1.StatusMetadataKey], + Name: fullUserNN.Name, + Error: fmt.Errorf("signature verification failed: %w", err), + } + nnc.workloadIDToProfileState.Set(toMerge.wlid, profileState) + // Restore cache to originalNN on user-managed verification failure + nnc.workloadIDToNetworkNeighborhood.Set(toMerge.wlid, originalNN) + return + } + } + // Merge the network neighborhoods mergedNN := nnc.performMerge(originalNN, fullUserNN) + + // Clear stale signature annotations after merge + delete(mergedNN.Annotations, signature.AnnotationSignature) + delete(mergedNN.Annotations, signature.AnnotationCertificate) + delete(mergedNN.Annotations, signature.AnnotationRekorBundle) + delete(mergedNN.Annotations, signature.AnnotationIssuer) + delete(mergedNN.Annotations, signature.AnnotationIdentity) + delete(mergedNN.Annotations, signature.AnnotationTimestamp) + // Update the cache with the merged network neighborhood nnc.workloadIDToNetworkNeighborhood.Set(toMerge.wlid, mergedNN) // Update profile state for the merged profile diff --git a/pkg/rulemanager/ruleswatcher/watcher.go b/pkg/rulemanager/ruleswatcher/watcher.go index 45782beb2..9d4c4b003 100644 --- a/pkg/rulemanager/ruleswatcher/watcher.go +++ b/pkg/rulemanager/ruleswatcher/watcher.go @@ -2,14 +2,18 @@ package ruleswatcher import ( "context" + "errors" "os" "github.com/Masterminds/semver/v3" "github.com/kubescape/go-logger" "github.com/kubescape/go-logger/helpers" + "github.com/kubescape/node-agent/pkg/config" "github.com/kubescape/node-agent/pkg/k8sclient" "github.com/kubescape/node-agent/pkg/rulemanager/rulecreator" typesv1 "github.com/kubescape/node-agent/pkg/rulemanager/types/v1" + "github.com/kubescape/node-agent/pkg/signature" + "github.com/kubescape/node-agent/pkg/signature/profiles" "github.com/kubescape/node-agent/pkg/watcher" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -22,14 +26,16 @@ var _ RulesWatcher = (*RulesWatcherImpl)(nil) type RulesWatcherImpl struct { ruleCreator rulecreator.RuleCreator k8sClient k8sclient.K8sClientInterface + cfg *config.Config callback RulesWatcherCallback watchResources []watcher.WatchResource } -func NewRulesWatcher(k8sClient k8sclient.K8sClientInterface, ruleCreator rulecreator.RuleCreator, callback RulesWatcherCallback) *RulesWatcherImpl { +func NewRulesWatcher(k8sClient k8sclient.K8sClientInterface, ruleCreator rulecreator.RuleCreator, callback RulesWatcherCallback, cfg *config.Config) *RulesWatcherImpl { return &RulesWatcherImpl{ ruleCreator: ruleCreator, k8sClient: k8sClient, + cfg: cfg, callback: callback, watchResources: []watcher.WatchResource{ watcher.NewWatchResource(typesv1.RuleGvr, metav1.ListOptions{}), @@ -71,7 +77,8 @@ func (w *RulesWatcherImpl) syncAllRulesAndNotify(ctx context.Context) { // syncAllRulesFromCluster fetches all rules from the cluster and syncs them with the rule creator. // Rules are filtered by: // 1. Enabled status - only enabled rules are considered -// 2. Agent version compatibility - rules with AgentVersionRequirement are checked against AGENT_VERSION env var using semver +// 2. Signature verification - if enabled, verifies rules have valid signatures +// 3. Agent version compatibility - rules with AgentVersionRequirement are checked against AGENT_VERSION env var using semver func (w *RulesWatcherImpl) syncAllRulesFromCluster(ctx context.Context) error { unstructuredList, err := w.k8sClient.GetDynamicClient().Resource(typesv1.RuleGvr).List(ctx, metav1.ListOptions{}) if err != nil { @@ -80,12 +87,20 @@ func (w *RulesWatcherImpl) syncAllRulesFromCluster(ctx context.Context) error { var enabledRules []typesv1.Rule var skippedVersionCount int + var skippedVerificationCount int for _, item := range unstructuredList.Items { rules, err := unstructuredToRules(&item) if err != nil { logger.L().Warning("RulesWatcher - failed to convert rule during sync", helpers.Error(err)) continue } + + // Verify signature if enabled + if err := w.verifyRules(rules); err != nil { + skippedVerificationCount++ + continue + } + for _, rule := range rules.Spec.Rules { if rule.Enabled { // Check agent version requirement if specified @@ -109,7 +124,8 @@ func (w *RulesWatcherImpl) syncAllRulesFromCluster(ctx context.Context) error { logger.L().Info("RulesWatcher - synced rules from cluster", helpers.Int("enabledRules", len(enabledRules)), helpers.Int("totalRules", len(unstructuredList.Items)), - helpers.Int("skippedByVersion", skippedVersionCount)) + helpers.Int("skippedByVersion", skippedVersionCount), + helpers.Int("skippedByVerification", skippedVerificationCount)) return nil } @@ -126,6 +142,30 @@ func unstructuredToRules(obj *unstructured.Unstructured) (*typesv1.Rules, error) return rule, nil } +func (w *RulesWatcherImpl) verifyRules(rules *typesv1.Rules) error { + if w.cfg == nil || !w.cfg.EnableSignatureVerification { + return nil + } + rulesAdapter := profiles.NewRulesAdapter(rules) + if err := signature.VerifyObject(rulesAdapter); err != nil { + if errors.Is(err, signature.ErrObjectNotSigned) { + logger.L().Debug("Rules resource is not signed, skipping", + helpers.String("name", rules.Name), + helpers.String("namespace", rules.Namespace)) + } else { + logger.L().Warning("Rules resource signature verification failed", + helpers.String("name", rules.Name), + helpers.String("namespace", rules.Namespace), + helpers.Error(err)) + } + return err + } + logger.L().Debug("Rules resource signature verification successful", + helpers.String("name", rules.Name), + helpers.String("namespace", rules.Namespace)) + return nil +} + // isAgentVersionCompatible checks if the current agent version satisfies the given requirement // using semantic versioning constraints. Returns true if compatible, false otherwise. func isAgentVersionCompatible(requirement string) bool { diff --git a/pkg/signature/annotations.go b/pkg/signature/annotations.go new file mode 100644 index 000000000..8df333d21 --- /dev/null +++ b/pkg/signature/annotations.go @@ -0,0 +1,16 @@ +package signature + +import "errors" + +const ( + AnnotationPrefix = "signature.kubescape.io" + + AnnotationSignature = AnnotationPrefix + "/signature" + AnnotationCertificate = AnnotationPrefix + "/certificate" + AnnotationRekorBundle = AnnotationPrefix + "/rekor-bundle" + AnnotationIssuer = AnnotationPrefix + "/issuer" + AnnotationIdentity = AnnotationPrefix + "/identity" + AnnotationTimestamp = AnnotationPrefix + "/timestamp" +) + +var ErrObjectNotSigned = errors.New("object is not signed (missing signature annotation)") diff --git a/pkg/signature/cluster_flow_test.go b/pkg/signature/cluster_flow_test.go new file mode 100644 index 000000000..23dfe8958 --- /dev/null +++ b/pkg/signature/cluster_flow_test.go @@ -0,0 +1,150 @@ +package signature + +import ( + "bytes" + "crypto" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "math/big" + "testing" + "time" + + sigstore_signature "github.com/sigstore/sigstore/pkg/signature" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/kubescape/node-agent/pkg/signature/profiles" + "github.com/kubescape/storage/pkg/apis/softwarecomposition/v1beta1" +) + +func TestClusterProfileStructure(t *testing.T) { + // Simulate a cluster profile with empty TypeMeta (like from cluster) + profile := &v1beta1.ApplicationProfile{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "", + Kind: "", + }, + } + profile.Name = "test-signed" + profile.Namespace = "default" + + adapter := profiles.NewApplicationProfileAdapter(profile) + content := adapter.GetContent() + + if m, ok := content.(map[string]interface{}); ok { + t.Logf("apiVersion: %v (type: %T)", m["apiVersion"], m["apiVersion"]) + t.Logf("kind: %v (type: %T)", m["kind"], m["kind"]) + + // Verify fallback values are applied + if m["apiVersion"] != "spdx.softwarecomposition.kubescape.io/v1beta1" { + t.Errorf("Expected fallback apiVersion, got %s", m["apiVersion"]) + } + if m["kind"] != "ApplicationProfile" { + t.Errorf("Expected fallback kind, got %s", m["kind"]) + } + } else { + t.Errorf("Expected map, got %T", content) + } +} + +func TestReproduceClusterVerificationFlow(t *testing.T) { + // Simulate the exact scenario from the cluster + profile := &v1beta1.ApplicationProfile{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "", + Kind: "", + }, + } + profile.Name = "replicaset-nginx2-5bffdcc777-signed" + profile.Namespace = "default" + profile.Labels = map[string]string{ + "kubescape.io/instance-template-hash": "5bffdcc777", + "kubescape.io/workload-api-group": "apps", + "kubescape.io/workload-api-version": "v1", + "kubescape.io/workload-kind": "Deployment", + "kubescape.io/workload-name": "nginx2", + "kubescape.io/workload-namespace": "default", + "kubescape.io/workload-resource-version": "15471", + } + + adapter := profiles.NewApplicationProfileAdapter(profile) + + // Calculate hash + cosignAdapter := &CosignAdapter{} + hash, err := cosignAdapter.GetContentHash(adapter.GetContent()) + if err != nil { + t.Fatalf("Failed to compute hash: %v", err) + } + + t.Logf("Computed hash: %s", hash) + + // Generate a key and sign + privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatalf("Failed to generate key: %v", err) + } + signer, err := sigstore_signature.LoadECDSASigner(privKey, crypto.SHA256) + if err != nil { + t.Fatalf("Failed to load signer: %v", err) + } + + sig, err := signer.SignMessage(bytes.NewReader([]byte(hash))) + if err != nil { + t.Fatalf("Failed to sign message: %v", err) + } + certBytes, err := generateTestCertificate(privKey) + if err != nil { + t.Fatalf("Failed to generate test certificate: %v", err) + } + + // Use the package-level annotation flow + sigObj := &Signature{ + Signature: sig, + Certificate: certBytes, + Timestamp: time.Now().Unix(), + } + annotations, err := cosignAdapter.EncodeSignatureToAnnotations(sigObj) + if err != nil { + t.Fatalf("Failed to encode signature to annotations: %v", err) + } + adapter.SetAnnotations(annotations) + + // Now verify using the higher-level flow + err = VerifyObjectAllowUntrusted(adapter) + if err != nil { + t.Fatalf("VerifyObjectAllowUntrusted failed: %v", err) + } +} + +func generateTestCertificate(privKey *ecdsa.PrivateKey) ([]byte, error) { + serialNumber, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128)) + if err != nil { + return nil, err + } + + template := x509.Certificate{ + SerialNumber: serialNumber, + Subject: pkix.Name{ + CommonName: "test-signer", + }, + NotBefore: time.Now(), + NotAfter: time.Now().Add(365 * 24 * time.Hour), + KeyUsage: x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning}, + } + + certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &privKey.PublicKey, privKey) + if err != nil { + return nil, err + } + + certPEM := pem.EncodeToMemory(&pem.Block{ + Type: "CERTIFICATE", + Bytes: certDER, + }) + + return certPEM, nil +} diff --git a/pkg/signature/cluster_scenario_test.go b/pkg/signature/cluster_scenario_test.go new file mode 100644 index 000000000..b26813d6d --- /dev/null +++ b/pkg/signature/cluster_scenario_test.go @@ -0,0 +1,88 @@ +package signature + +import ( + "testing" + + "github.com/kubescape/node-agent/pkg/signature/profiles" + "github.com/kubescape/storage/pkg/apis/softwarecomposition/v1beta1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// This test replicates the exact scenario from the production cluster where: +// 1. Profiles are loaded from the cluster with empty TypeMeta (APIVersion="", Kind="") +// 2. The adapter's GetContent() should fill in the correct fallback values +// 3. Signatures created and verified using these profiles should succeed + +func TestClusterScenarioIntegration(t *testing.T) { + // Simulate a profile as it comes from the cluster (empty TypeMeta) + clusterProfile := &v1beta1.ApplicationProfile{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "", + Kind: "", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "replicaset-test-workload-123456789", + Namespace: "default", + Labels: map[string]string{ + "kubescape.io/instance-template-hash": "123456789", + "kubescape.io/workload-kind": "Deployment", + "kubescape.io/workload-name": "test-workload", + "kubescape.io/workload-namespace": "default", + }, + }, + } + + // Create adapter + adapter := profiles.NewApplicationProfileAdapter(clusterProfile) + + // Verify GetContent() populates TypeMeta correctly + content := adapter.GetContent() + contentMap, ok := content.(map[string]interface{}) + if !ok { + t.Fatalf("GetContent() should return map[string]interface{}, got %T", content) + } + + // Check that fallback values are applied + if contentMap["apiVersion"] != "spdx.softwarecomposition.kubescape.io/v1beta1" { + t.Errorf("Expected apiVersion fallback to be applied, got: %v", contentMap["apiVersion"]) + } + if contentMap["kind"] != "ApplicationProfile" { + t.Errorf("Expected kind fallback to be applied, got: %v", contentMap["kind"]) + } + + // Verify metadata is correctly structured + metadata, ok := contentMap["metadata"].(map[string]interface{}) + if !ok { + t.Fatal("metadata should be a map[string]interface{}") + } + + if metadata["name"] != clusterProfile.Name { + t.Errorf("Expected metadata.name=%s, got %v", clusterProfile.Name, metadata["name"]) + } + if metadata["namespace"] != clusterProfile.Namespace { + t.Errorf("Expected metadata.namespace=%s, got %v", clusterProfile.Namespace, metadata["namespace"]) + } + if metadata["labels"] == nil { + t.Error("metadata.labels should not be nil") + } + + // Now verify that signing and verification work end-to-end + if err := SignObjectDisableKeyless(adapter); err != nil { + t.Fatalf("Failed to sign object: %v", err) + } + + if clusterProfile.Annotations == nil { + t.Fatal("Annotations should be set after signing") + } + + if _, ok := clusterProfile.Annotations[AnnotationSignature]; !ok { + t.Error("Signature annotation should be set after signing") + } + + // Verify the signature + if err := VerifyObjectAllowUntrusted(adapter); err != nil { + t.Fatalf("Failed to verify object: %v", err) + } + + t.Log("✓ Cluster scenario integration test passed: profile with empty TypeMeta successfully signed and verified") +} diff --git a/pkg/signature/cosign_adapter.go b/pkg/signature/cosign_adapter.go new file mode 100644 index 000000000..b78d8920a --- /dev/null +++ b/pkg/signature/cosign_adapter.go @@ -0,0 +1,572 @@ +package signature + +import ( + "bytes" + "crypto" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/x509" + "crypto/x509/pkix" + "encoding/base64" + "encoding/json" + "encoding/pem" + "fmt" + "math/big" + "net/url" + "strconv" + "time" + + "context" + "github.com/golang-jwt/jwt/v5" + "github.com/kubescape/storage/pkg/utils" + "github.com/sigstore/cosign/v3/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign/bundle" + "github.com/sigstore/cosign/v3/pkg/providers" + _ "github.com/sigstore/cosign/v3/pkg/providers/all" + "github.com/sigstore/fulcio/pkg/api" + "github.com/sigstore/rekor/pkg/generated/client" + "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/sigstore/pkg/cryptoutils" + "github.com/sigstore/sigstore/pkg/fulcioroots" + "github.com/sigstore/sigstore/pkg/oauthflow" + sigstore_signature "github.com/sigstore/sigstore/pkg/signature" +) + +var _ = cosign.Signature +var _ = providers.Enabled +var _ = bundle.RekorBundle{} +var _ = api.CertificateRequest{} +var _ = client.Rekor{} +var _ = models.LogEntry{} +var _ = fulcioroots.Get +var _ = oauthflow.OIDConnect +var _ = oauthflow.DefaultIDTokenGetter + +const ( + sigstoreIssuer = "https://token.actions.githubusercontent.com" + sigstoreOIDC = "kubernetes.io" + fulcioURL = "https://fulcio.sigstore.dev" + rekorURL = "https://rekor.sigstore.dev" +) + +type CosignAdapter struct { + privateKey *ecdsa.PrivateKey + signer sigstore_signature.Signer + verifier sigstore_signature.Verifier + useKeyless bool + tokenProvider func(ctx context.Context) (string, error) +} + +func NewCosignAdapter(useKeyless bool) (*CosignAdapter, error) { + if useKeyless { + return &CosignAdapter{ + useKeyless: true, + }, nil + } + + privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + return nil, fmt.Errorf("failed to generate private key: %w", err) + } + + signer, err := sigstore_signature.LoadECDSASigner(privateKey, crypto.SHA256) + if err != nil { + return nil, fmt.Errorf("failed to load ECDSA signer: %w", err) + } + + verifier, err := sigstore_signature.LoadECDSAVerifier(&privateKey.PublicKey, crypto.SHA256) + if err != nil { + return nil, fmt.Errorf("failed to load ECDSA verifier: %w", err) + } + + return &CosignAdapter{ + privateKey: privateKey, + signer: signer, + verifier: verifier, + useKeyless: false, + }, nil +} + +func NewCosignAdapterWithPrivateKey(useKeyless bool, privateKey *ecdsa.PrivateKey) (*CosignAdapter, error) { + if privateKey == nil { + return nil, fmt.Errorf("private key cannot be nil") + } + + signer, err := sigstore_signature.LoadECDSASigner(privateKey, crypto.SHA256) + if err != nil { + return nil, fmt.Errorf("failed to load ECDSA signer: %w", err) + } + + verifier, err := sigstore_signature.LoadECDSAVerifier(&privateKey.PublicKey, crypto.SHA256) + if err != nil { + return nil, fmt.Errorf("failed to load ECDSA verifier: %w", err) + } + + return &CosignAdapter{ + privateKey: privateKey, + signer: signer, + verifier: verifier, + useKeyless: useKeyless, + }, nil +} + +func (c *CosignAdapter) SignData(data []byte) (*Signature, error) { + if c.useKeyless { + return c.signKeyless(data) + } + + return c.signWithKey(data) +} + +func (c *CosignAdapter) SetTokenProvider(provider func(context.Context) (string, error)) { + c.tokenProvider = provider +} + +func (c *CosignAdapter) signKeyless(data []byte) (*Signature, error) { + ctx := context.Background() + + var tok string + var err error + var identity string + var issuer string + + // 1. Get OIDC Token + if c.tokenProvider != nil { + tok, err = c.tokenProvider(ctx) + if err != nil { + return nil, fmt.Errorf("failed to provide OIDC token from provider: %w", err) + } + } else if providers.Enabled(ctx) { + tok, err = providers.Provide(ctx, "sigstore") + if err != nil { + return nil, fmt.Errorf("failed to provide OIDC token: %w", err) + } + } + + if tok != "" { + // Extract "sub" and "iss" from the JWT token + parser := jwt.NewParser() + token, _, err := parser.ParseUnverified(tok, jwt.MapClaims{}) + if err != nil { + return nil, fmt.Errorf("failed to parse OIDC token: %w", err) + } + + claims, ok := token.Claims.(jwt.MapClaims) + if !ok { + return nil, fmt.Errorf("failed to get claims from OIDC token") + } + + sub, ok := claims["sub"].(string) + if !ok { + return nil, fmt.Errorf("failed to get 'sub' claim from OIDC token") + } + identity = sub + + iss, ok := claims["iss"].(string) + if !ok { + return nil, fmt.Errorf("failed to get 'iss' claim from OIDC token") + } + issuer = iss + } else { + // Fallback to interactive flow if not in CI and no provider + fmt.Println("No OIDC provider enabled (CI). Falling back to interactive flow...") + // Sigstore's default issuer and client ID + issuerURL := "https://oauth2.sigstore.dev/auth" + clientID := "sigstore" + // This will open a browser window for authentication + oidcToken, err := oauthflow.OIDConnect(issuerURL, clientID, "", "", oauthflow.DefaultIDTokenGetter) + if err != nil { + return nil, fmt.Errorf("failed to get interactive OIDC token: %w", err) + } + tok = oidcToken.RawString + identity = oidcToken.Subject + issuer = issuerURL + } + _ = tok + + // 2. Generate Ephemeral Key Pair + privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + return nil, fmt.Errorf("failed to generate ephemeral key: %w", err) + } + signer, err := sigstore_signature.LoadECDSASigner(privKey, crypto.SHA256) + if err != nil { + return nil, fmt.Errorf("failed to load ephemeral signer: %w", err) + } + + // 3. Get Certificate from Fulcio using the real client + certBytes, err := c.getFulcioCertificate(ctx, privKey, identity, tok) + if err != nil { + return nil, fmt.Errorf("failed to get certificate from Fulcio: %w", err) + } + + // 4. Sign Data + sig, err := signer.SignMessage(bytes.NewReader(data)) + if err != nil { + return nil, fmt.Errorf("failed to sign data: %w", err) + } + + // 5. Upload to Rekor (Placeholder for real upload) + // rekorClient, _ := rekor.GetByProxy(rekorURL) + // entry, _ := cosign.TLogUpload(ctx, rekorClient, sig, certBytes, data) + + return &Signature{ + Signature: sig, + Certificate: certBytes, + Issuer: issuer, + Identity: identity, + Timestamp: time.Now().Unix(), + }, nil +} + +func (c *CosignAdapter) simulateKeyless(data []byte) (*Signature, error) { + return nil, fmt.Errorf("simulateKeyless is deprecated, use real keyless signing") +} + +func (c *CosignAdapter) signWithKey(data []byte) (*Signature, error) { + sig, err := c.signer.SignMessage(bytes.NewReader(data)) + if err != nil { + return nil, fmt.Errorf("failed to sign message: %w", err) + } + + certBytes, err := c.generateCertificate(c.privateKey, "local-key", "local") + if err != nil { + return nil, fmt.Errorf("failed to generate certificate: %w", err) + } + + sigObj := &Signature{ + Signature: sig, + Certificate: certBytes, + Issuer: "local", + Identity: "local-key", + Timestamp: time.Now().Unix(), + } + + return sigObj, nil +} + +func (c *CosignAdapter) getFulcioCertificate(ctx context.Context, privKey *ecdsa.PrivateKey, identity, oidcToken string) ([]byte, error) { + // Parse Fulcio URL + fulcioAddr, err := url.Parse(fulcioURL) + if err != nil { + return nil, fmt.Errorf("failed to parse Fulcio URL: %w", err) + } + + // Create Fulcio client + fulcioClient := api.NewClient(fulcioAddr) + + // Marshal public key to ASN.1 DER format + pubKeyBytes, err := x509.MarshalPKIXPublicKey(&privKey.PublicKey) + if err != nil { + return nil, fmt.Errorf("failed to marshal public key: %w", err) + } + + // Create CertificateRequest with the public key + certReq := api.CertificateRequest{ + PublicKey: api.Key{ + Content: pubKeyBytes, + Algorithm: "ecdsa", + }, + } + + // We need to prove possession of the OIDC token's identity by signing the identity + // Fulcio expects a signature over the identity (e.g. email or subject) + proof, err := c.ecdsaSign(privKey, []byte(identity)) + if err != nil { + return nil, fmt.Errorf("failed to sign identity for proof: %w", err) + } + certReq.SignedEmailAddress = proof + + // Call Fulcio API to get certificate + certResp, err := fulcioClient.SigningCert(certReq, oidcToken) + if err != nil { + return nil, fmt.Errorf("Fulcio SigningCert failed: %w", err) + } + + return certResp.CertPEM, nil +} + +func (c *CosignAdapter) generateCertificate(privKey *ecdsa.PrivateKey, identity, issuer string) ([]byte, error) { + serialNumber, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128)) + if err != nil { + return nil, fmt.Errorf("failed to generate serial number: %w", err) + } + + template := x509.Certificate{ + SerialNumber: serialNumber, + Subject: pkix.Name{ + CommonName: identity, + }, + NotBefore: time.Now(), + NotAfter: time.Now().Add(365 * 24 * time.Hour), + KeyUsage: x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning}, + BasicConstraintsValid: true, + } + + certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &privKey.PublicKey, privKey) + if err != nil { + return nil, fmt.Errorf("failed to create certificate: %w", err) + } + + certPEM := pem.EncodeToMemory(&pem.Block{ + Type: "CERTIFICATE", + Bytes: certDER, + }) + + return certPEM, nil +} + +func (c *CosignAdapter) ecdsaSign(privKey *ecdsa.PrivateKey, data []byte) ([]byte, error) { + signer, err := sigstore_signature.LoadECDSASigner(privKey, crypto.SHA256) + if err != nil { + return nil, err + } + return signer.SignMessage(bytes.NewReader(data)) +} + +func (c *CosignAdapter) GetPrivateKeyPEM() ([]byte, error) { + if c.privateKey == nil { + return nil, fmt.Errorf("no private key available") + } + + derBytes, err := x509.MarshalECPrivateKey(c.privateKey) + if err != nil { + return nil, fmt.Errorf("failed to marshal private key: %w", err) + } + + block := &pem.Block{ + Type: "EC PRIVATE KEY", + Bytes: derBytes, + } + + return pem.EncodeToMemory(block), nil +} + +func (c *CosignAdapter) GetPublicKeyPEM() ([]byte, error) { + if c.privateKey == nil { + return nil, fmt.Errorf("no private key available") + } + + pubKeyBytes, err := cryptoutils.MarshalPublicKeyToPEM(&c.privateKey.PublicKey) + if err != nil { + return nil, fmt.Errorf("failed to marshal public key: %w", err) + } + + return pubKeyBytes, nil +} + +func (c *CosignAdapter) VerifyData(data []byte, sig *Signature, allowUntrusted bool) error { + if sig == nil { + return fmt.Errorf("VerifyData: Signature value is nil") + } + if len(sig.Certificate) == 0 { + return fmt.Errorf("VerifyData: Signature.Certificate is empty") + } + + var verifier sigstore_signature.Verifier + var err error + + // If we have a certificate, it could be a keyless signature (Fulcio) or a key-based signature with a cert. + // For keyless, we should ideally verify the certificate chain and Rekor bundle. + // For now, we continue to support the simplified verification but using sigstore's abstractions. + + block, _ := pem.Decode(sig.Certificate) + if block != nil && block.Type == "CERTIFICATE" { + var cert *x509.Certificate + cert, err = x509.ParseCertificate(block.Bytes) + if err != nil { + return fmt.Errorf("failed to parse certificate: %w", err) + } + + if !allowUntrusted { + if cert.IsCA { + return fmt.Errorf("invalid certificate: must not be CA") + } + + // Build and verify the certificate chain + roots, err := fulcioroots.Get() + if err != nil { + return fmt.Errorf("failed to get Fulcio roots: %w", err) + } + opts := x509.VerifyOptions{ + Roots: roots, + KeyUsages: []x509.ExtKeyUsage{ + x509.ExtKeyUsageCodeSigning, + }, + CurrentTime: time.Unix(sig.Timestamp, 0), + } + if _, err := cert.Verify(opts); err != nil { + return fmt.Errorf("failed to verify certificate chain: %w", err) + } + + if time.Unix(sig.Timestamp, 0).Before(cert.NotBefore) || time.Unix(sig.Timestamp, 0).After(cert.NotAfter) { + return fmt.Errorf("certificate was not valid at signing time") + } + + // In a production environment, we would verify the certificate chain here + // against the Fulcio root set and system roots. + // roots, _ := fulcioroots.Get() + // cert.Verify(x509.VerifyOptions{Roots: roots}) + + // Check identity. Fulcio certs store identity in Subject Alternative Name (SAN) + // but many systems still look at CommonName or use specific extensions. + // Sigstore's verify library is usually used for this, but for now we'll check SANs. + foundIdentity := false + if cert.Subject.CommonName == sig.Identity { + foundIdentity = true + } else { + for _, email := range cert.EmailAddresses { + if email == sig.Identity { + foundIdentity = true + break + } + } + if !foundIdentity { + for _, uri := range cert.URIs { + if uri.String() == sig.Identity { + foundIdentity = true + break + } + } + } + } + + if sig.Identity != "" && !foundIdentity { + return fmt.Errorf("identity mismatch: certificate does not match signature identity %q (CN: %q, SANs: %v)", sig.Identity, cert.Subject.CommonName, cert.EmailAddresses) + } + + // Validate Rekor/CT evidence if Rekor bundle is present + if len(sig.RekorBundle) > 0 { + // In a full implementation, we would use cosign.VerifyBundle + // for now we acknowledge its presence for strict verification + } else if sig.Issuer != "local" && sig.Issuer != "" { + // For non-local certificates, we expect a Rekor bundle in strict mode + // But we'll allow it if we are in interactive mode (where Rekor might not be used) + if sig.Issuer != "https://oauth2.sigstore.dev/auth" { + return fmt.Errorf("strict verification failed: missing Rekor bundle for certificate from %q", sig.Issuer) + } + } + } + verifier, err = sigstore_signature.LoadVerifier(cert.PublicKey, crypto.SHA256) + if err != nil { + return fmt.Errorf("failed to load verifier from certificate: %w", err) + } + } else { + // If not a certificate, it must be a public key + if !allowUntrusted { + return fmt.Errorf("untrusted public key rejected: require valid x509 certificate chain") + } + + pubKey, err := cryptoutils.UnmarshalPEMToPublicKey(sig.Certificate) + if err != nil { + // Try parsing as raw DER + pubKey, err = x509.ParsePKIXPublicKey(sig.Certificate) + if err != nil { + return fmt.Errorf("failed to unmarshal public key: %w", err) + } + } + + verifier, err = sigstore_signature.LoadVerifier(pubKey, crypto.SHA256) + if err != nil { + return fmt.Errorf("failed to load verifier: %w", err) + } + } + + if err := verifier.VerifySignature(bytes.NewReader(sig.Signature), bytes.NewReader(data)); err != nil { + return fmt.Errorf("invalid signature: %w", err) + } + + // In a full Cosign implementation, if we have a Rekor bundle, we would verify it here. + // sig.RekorBundle (if added to the Signature struct) could be used with cosign/pkg/cosign.VerifyBundle. + + if c.useKeyless && !allowUntrusted { + if sig.Issuer == "" || sig.Identity == "" { + return fmt.Errorf("keyless signature missing issuer or identity") + } + } + + return nil +} + +func (c *CosignAdapter) GetContentHash(obj interface{}) (string, error) { + data, err := json.Marshal(obj) + if err != nil { + return "", fmt.Errorf("failed to marshal object: %w", err) + } + + hash, err := utils.CanonicalHash(data) + if err != nil { + return "", err + } + + return hash, nil +} + +func (c *CosignAdapter) EncodeSignatureToAnnotations(sig *Signature) (map[string]string, error) { + annotations := make(map[string]string) + + annotations[AnnotationSignature] = base64.StdEncoding.EncodeToString(sig.Signature) + + if len(sig.Certificate) > 0 { + annotations[AnnotationCertificate] = base64.StdEncoding.EncodeToString(sig.Certificate) + } + if len(sig.RekorBundle) > 0 { + annotations[AnnotationRekorBundle] = base64.StdEncoding.EncodeToString(sig.RekorBundle) + } + if sig.Issuer != "" { + annotations[AnnotationIssuer] = sig.Issuer + } + if sig.Identity != "" { + annotations[AnnotationIdentity] = sig.Identity + } + annotations[AnnotationTimestamp] = fmt.Sprintf("%d", sig.Timestamp) + + return annotations, nil +} + +func (c *CosignAdapter) DecodeSignatureFromAnnotations(annotations map[string]string) (*Signature, error) { + sig := &Signature{} + + signatureB64, ok := annotations[AnnotationSignature] + if !ok { + return nil, fmt.Errorf("missing %s annotation", AnnotationSignature) + } + + var err error + sig.Signature, err = base64.StdEncoding.DecodeString(signatureB64) + if err != nil { + // Try raw if base64 fails + sig.Signature = []byte(signatureB64) + } + + if certB64, ok := annotations[AnnotationCertificate]; ok { + sig.Certificate, err = base64.StdEncoding.DecodeString(certB64) + if err != nil { + // Try raw if base64 fails + sig.Certificate = []byte(certB64) + } + } + + if rekorB64, ok := annotations[AnnotationRekorBundle]; ok { + sig.RekorBundle, err = base64.StdEncoding.DecodeString(rekorB64) + if err != nil { + // Try raw if base64 fails + sig.RekorBundle = []byte(rekorB64) + } + } + + sig.Issuer = annotations[AnnotationIssuer] + sig.Identity = annotations[AnnotationIdentity] + + if timestamp, ok := annotations[AnnotationTimestamp]; ok { + ts, err := strconv.ParseInt(timestamp, 10, 64) + if err != nil { + return nil, fmt.Errorf("failed to parse timestamp: %w", err) + } + sig.Timestamp = ts + } + + return sig, nil +} diff --git a/pkg/signature/cosign_adapter_test.go b/pkg/signature/cosign_adapter_test.go new file mode 100644 index 000000000..b125f5175 --- /dev/null +++ b/pkg/signature/cosign_adapter_test.go @@ -0,0 +1,143 @@ +package signature + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/x509" + "testing" +) + +func TestNewCosignAdapterWithPrivateKey(t *testing.T) { + privKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + + t.Run("Valid private key", func(t *testing.T) { + adapter, err := NewCosignAdapterWithPrivateKey(false, privKey) + if err != nil { + t.Fatalf("Expected no error, got %v", err) + } + if adapter.privateKey != privKey { + t.Error("Private key not set correctly") + } + }) + + t.Run("Nil private key", func(t *testing.T) { + _, err := NewCosignAdapterWithPrivateKey(false, nil) + if err == nil { + t.Error("Expected error for nil private key, got nil") + } + }) +} + +func TestCosignAdapter_GetKeysPEM(t *testing.T) { + privKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + adapter, _ := NewCosignAdapterWithPrivateKey(false, privKey) + + t.Run("GetPrivateKeyPEM", func(t *testing.T) { + pem, err := adapter.GetPrivateKeyPEM() + if err != nil { + t.Fatalf("Expected no error, got %v", err) + } + if len(pem) == 0 { + t.Error("Expected non-empty PEM") + } + }) + + t.Run("GetPublicKeyPEM", func(t *testing.T) { + pem, err := adapter.GetPublicKeyPEM() + if err != nil { + t.Fatalf("Expected no error, got %v", err) + } + if len(pem) == 0 { + t.Error("Expected non-empty PEM") + } + }) + + t.Run("No private key", func(t *testing.T) { + emptyAdapter := &CosignAdapter{} + _, err := emptyAdapter.GetPrivateKeyPEM() + if err == nil { + t.Error("Expected error, got nil") + } + _, err = emptyAdapter.GetPublicKeyPEM() + if err == nil { + t.Error("Expected error, got nil") + } + }) +} + +func TestWithPrivateKey(t *testing.T) { + privKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + opts := &SignOptions{} + WithPrivateKey(privKey)(opts) + if opts.PrivateKey != privKey { + t.Error("PrivateKey option not set correctly") + } +} + +func TestCosignSigner(t *testing.T) { + signer, err := NewCosignSigner(false) + if err != nil { + t.Fatalf("Expected no error, got %v", err) + } + + data := []byte("test data") + sig, err := signer.Sign(data) + if err != nil { + t.Fatalf("Expected no error, got %v", err) + } + if len(sig.Signature) == 0 { + t.Error("Expected non-empty signature") + } +} + +func TestCosignAdapter_ecdsaSign(t *testing.T) { + privKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + adapter := &CosignAdapter{} + data := []byte("test data") + sig, err := adapter.ecdsaSign(privKey, data) + if err != nil { + t.Fatalf("Expected no error, got %v", err) + } + if len(sig) == 0 { + t.Error("Expected non-empty signature") + } +} + +func TestVerifyData_ErrorCases(t *testing.T) { + privKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + adapter, _ := NewCosignAdapterWithPrivateKey(false, privKey) + data := []byte("test data") + + t.Run("Invalid certificate PEM", func(t *testing.T) { + sig := &Signature{ + Signature: []byte("sig"), + Certificate: []byte("invalid-pem"), + } + err := adapter.VerifyData(data, sig, false) + if err == nil { + t.Error("Expected error for invalid certificate PEM, got nil") + } + }) + + t.Run("PublicKey is not ECDSA", func(t *testing.T) { + // Mock a non-ECDSA public key? Hard to do with current implementation. + // Skipping for now. + }) + + t.Run("Certificate is CA", func(t *testing.T) { + // Create a CA certificate + template := x509.Certificate{ + IsCA: true, + } + certDER, _ := x509.CreateCertificate(rand.Reader, &template, &template, &privKey.PublicKey, privKey) + sig := &Signature{ + Signature: []byte("sig"), + Certificate: certDER, + } + err := adapter.VerifyData(data, sig, false) + if err == nil { + t.Error("Expected error for CA certificate, got nil") + } + }) +} diff --git a/pkg/signature/interface.go b/pkg/signature/interface.go new file mode 100644 index 000000000..720ca7a59 --- /dev/null +++ b/pkg/signature/interface.go @@ -0,0 +1,63 @@ +package signature + +import ( + "crypto/ecdsa" +) + +type Signer interface { + Sign(data []byte) (*Signature, error) +} + +type Verifier interface { + Verify(data []byte, sig *Signature) error +} + +type SignableObject interface { + GetAnnotations() map[string]string + SetAnnotations(annotations map[string]string) + GetUID() string + GetNamespace() string + GetName() string + GetContent() interface{} + GetUpdatedObject() interface{} +} + +type Signature struct { + Signature []byte + Certificate []byte + RekorBundle []byte + Issuer string + Identity string + Timestamp int64 +} + +type SignOptions struct { + UseKeyless bool + PrivateKey *ecdsa.PrivateKey +} + +type SignOption func(*SignOptions) + +func WithKeyless(useKeyless bool) SignOption { + return func(opts *SignOptions) { + opts.UseKeyless = useKeyless + } +} + +func WithPrivateKey(privateKey *ecdsa.PrivateKey) SignOption { + return func(opts *SignOptions) { + opts.PrivateKey = privateKey + } +} + +type VerifyOptions struct { + AllowUntrusted bool +} + +type VerifyOption func(*VerifyOptions) + +func WithUntrusted(allowUntrusted bool) VerifyOption { + return func(opts *VerifyOptions) { + opts.AllowUntrusted = allowUntrusted + } +} diff --git a/pkg/signature/profiles/adapter_test.go b/pkg/signature/profiles/adapter_test.go new file mode 100644 index 000000000..0f9af9168 --- /dev/null +++ b/pkg/signature/profiles/adapter_test.go @@ -0,0 +1,335 @@ +package profiles + +import ( + "testing" + + "github.com/kubescape/node-agent/pkg/signature" + "github.com/kubescape/storage/pkg/apis/softwarecomposition/v1beta1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" +) + +func TestApplicationProfileAdapter(t *testing.T) { + profile := &v1beta1.ApplicationProfile{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "softwarecomposition.kubescape.io/v1beta1", + Kind: "ApplicationProfile", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "test-ap", + Namespace: "default", + UID: types.UID("ap-uid-123"), + Labels: map[string]string{ + "app": "test", + }, + }, + Spec: v1beta1.ApplicationProfileSpec{ + Architectures: []string{"amd64"}, + Containers: []v1beta1.ApplicationProfileContainer{ + { + Name: "nginx", + Capabilities: []string{"CAP_NET_BIND_SERVICE"}, + }, + }, + }, + } + + adapter := NewApplicationProfileAdapter(profile) + + if adapter == nil { + t.Fatal("Expected non-nil adapter") + } + + if adapter.GetUID() != "ap-uid-123" { + t.Errorf("Expected UID 'ap-uid-123', got '%s'", adapter.GetUID()) + } + + if adapter.GetNamespace() != "default" { + t.Errorf("Expected namespace 'default', got '%s'", adapter.GetNamespace()) + } + + if adapter.GetName() != "test-ap" { + t.Errorf("Expected name 'test-ap', got '%s'", adapter.GetName()) + } + + annotations := adapter.GetAnnotations() + if annotations == nil { + t.Error("Expected annotations map, got nil") + } + + testAnnotations := map[string]string{ + "test-key": "test-value", + } + adapter.SetAnnotations(testAnnotations) + if profile.Annotations["test-key"] != "test-value" { + t.Error("Failed to set annotations") + } + + content := adapter.GetContent() + if content == nil { + t.Fatal("Expected non-nil content") + } + + apContent, ok := content.(map[string]interface{}) + if !ok { + t.Fatal("Expected map[string]interface{} content type") + } + + metadata, ok := apContent["metadata"].(map[string]interface{}) + if !ok { + t.Fatal("Expected metadata to be map[string]interface{}") + } + + if metadata["name"] != "test-ap" { + t.Errorf("Expected content name 'test-ap', got '%v'", metadata["name"]) + } + + if metadata["namespace"] != "default" { + t.Errorf("Expected content namespace 'default', got '%v'", metadata["namespace"]) + } + + if apContent["apiVersion"] != "softwarecomposition.kubescape.io/v1beta1" { + t.Errorf("Expected apiVersion 'softwarecomposition.kubescape.io/v1beta1', got '%v'", apContent["apiVersion"]) + } + + if apContent["kind"] != "ApplicationProfile" { + t.Errorf("Expected kind 'ApplicationProfile', got '%v'", apContent["kind"]) + } +} + +func TestApplicationProfileAdapterSignAndVerify(t *testing.T) { + profile := &v1beta1.ApplicationProfile{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "softwarecomposition.kubescape.io/v1beta1", + Kind: "ApplicationProfile", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "sign-test-ap", + Namespace: "default", + UID: types.UID("sign-ap-uid"), + Labels: map[string]string{ + "test": "signing", + }, + }, + Spec: v1beta1.ApplicationProfileSpec{ + Architectures: []string{"amd64", "arm64"}, + Containers: []v1beta1.ApplicationProfileContainer{ + { + Name: "app", + Capabilities: []string{"CAP_NET_ADMIN"}, + }, + }, + }, + } + + adapter := NewApplicationProfileAdapter(profile) + + err := signature.SignObjectDisableKeyless(adapter) + if err != nil { + t.Fatalf("SignObjectDisableKeyless failed: %v", err) + } + + if profile.Annotations == nil { + t.Error("Expected annotations to be set on profile") + } + + if _, ok := profile.Annotations[signature.AnnotationSignature]; !ok { + t.Error("Expected signature annotation on profile") + } + + err = signature.VerifyObjectAllowUntrusted(adapter) + if err != nil { + t.Fatalf("VerifyObjectAllowUntrusted failed: %v", err) + } +} + +func TestSeccompProfileAdapter(t *testing.T) { + profile := &v1beta1.SeccompProfile{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "softwarecomposition.kubescape.io/v1beta1", + Kind: "SeccompProfile", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "test-seccomp", + Namespace: "default", + UID: types.UID("seccomp-uid-456"), + Labels: map[string]string{ + "seccomp": "test", + }, + }, + Spec: v1beta1.SeccompProfileSpec{ + Containers: []v1beta1.SingleSeccompProfile{ + { + Name: "test-container", + }, + }, + }, + } + + adapter := NewSeccompProfileAdapter(profile) + + if adapter == nil { + t.Fatal("Expected non-nil adapter") + } + + if adapter.GetUID() != "seccomp-uid-456" { + t.Errorf("Expected UID 'seccomp-uid-456', got '%s'", adapter.GetUID()) + } + + if adapter.GetNamespace() != "default" { + t.Errorf("Expected namespace 'default', got '%s'", adapter.GetNamespace()) + } + + if adapter.GetName() != "test-seccomp" { + t.Errorf("Expected name 'test-seccomp', got '%s'", adapter.GetName()) + } + + annotations := adapter.GetAnnotations() + if annotations == nil { + t.Error("Expected annotations map, got nil") + } + + testAnnotations := map[string]string{ + "seccomp-key": "seccomp-value", + } + adapter.SetAnnotations(testAnnotations) + if profile.Annotations["seccomp-key"] != "seccomp-value" { + t.Error("Failed to set annotations") + } + + content := adapter.GetContent() + if content == nil { + t.Fatal("Expected non-nil content") + } + + scContent, ok := content.(map[string]interface{}) + if !ok { + t.Fatal("Expected map[string]interface{} content type") + } + + metadata, ok := scContent["metadata"].(map[string]interface{}) + if !ok { + t.Fatal("Expected metadata to be map[string]interface{}") + } + + if metadata["name"] != "test-seccomp" { + t.Errorf("Expected content name 'test-seccomp', got '%v'", metadata["name"]) + } + + if metadata["namespace"] != "default" { + t.Errorf("Expected content namespace 'default', got '%v'", metadata["namespace"]) + } + + if scContent["apiVersion"] != "softwarecomposition.kubescape.io/v1beta1" { + t.Errorf("Expected apiVersion 'softwarecomposition.kubescape.io/v1beta1', got '%v'", scContent["apiVersion"]) + } + + if scContent["kind"] != "SeccompProfile" { + t.Errorf("Expected kind 'SeccompProfile', got '%v'", scContent["kind"]) + } +} + +func TestSeccompProfileAdapterSignAndVerify(t *testing.T) { + profile := &v1beta1.SeccompProfile{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "softwarecomposition.kubescape.io/v1beta1", + Kind: "SeccompProfile", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "sign-test-seccomp", + Namespace: "default", + UID: types.UID("sign-seccomp-uid"), + Labels: map[string]string{ + "test": "seccomp-signing", + }, + }, + Spec: v1beta1.SeccompProfileSpec{ + Containers: []v1beta1.SingleSeccompProfile{ + { + Name: "app-container", + }, + }, + }, + } + + adapter := NewSeccompProfileAdapter(profile) + + err := signature.SignObjectDisableKeyless(adapter) + if err != nil { + t.Fatalf("SignObjectDisableKeyless failed: %v", err) + } + + if profile.Annotations == nil { + t.Error("Expected annotations to be set on profile") + } + + if _, ok := profile.Annotations[signature.AnnotationSignature]; !ok { + t.Error("Expected signature annotation on profile") + } + + err = signature.VerifyObjectAllowUntrusted(adapter) + if err != nil { + t.Fatalf("VerifyObjectAllowUntrusted failed: %v", err) + } +} + +func TestAdapterUniqueness(t *testing.T) { + ap := &v1beta1.ApplicationProfile{ + ObjectMeta: metav1.ObjectMeta{ + Name: "unique-ap", + Namespace: "default", + UID: types.UID("ap-unique-uid"), + }, + Spec: v1beta1.ApplicationProfileSpec{ + Architectures: []string{"amd64"}, + }, + } + + sp := &v1beta1.SeccompProfile{ + ObjectMeta: metav1.ObjectMeta{ + Name: "unique-sp", + Namespace: "default", + UID: types.UID("sp-unique-uid"), + }, + Spec: v1beta1.SeccompProfileSpec{}, + } + + apAdapter := NewApplicationProfileAdapter(ap) + spAdapter := NewSeccompProfileAdapter(sp) + + err := signature.SignObjectDisableKeyless(apAdapter) + if err != nil { + t.Fatalf("SignObjectDisableKeyless failed for ApplicationProfile: %v", err) + } + + err = signature.SignObjectDisableKeyless(spAdapter) + if err != nil { + t.Fatalf("SignObjectDisableKeyless failed for SeccompProfile: %v", err) + } + + apSig, err := signature.GetObjectSignature(apAdapter) + if err != nil { + t.Fatalf("GetObjectSignature failed for ApplicationProfile: %v", err) + } + + if apSig == nil { + t.Fatal("GetObjectSignature returned nil for ApplicationProfile") + } + + spSig, err := signature.GetObjectSignature(spAdapter) + if err != nil { + t.Fatalf("GetObjectSignature failed for SeccompProfile: %v", err) + } + + if spSig == nil { + t.Fatal("GetObjectSignature returned nil for SeccompProfile") + } + + if apSig.Issuer != "local" { + t.Errorf("Expected AP issuer 'local', got '%s'", apSig.Issuer) + } + + if spSig.Issuer != "local" { + t.Errorf("Expected SP issuer 'local', got '%s'", spSig.Issuer) + } +} diff --git a/pkg/signature/profiles/applicationprofile_adapter.go b/pkg/signature/profiles/applicationprofile_adapter.go new file mode 100644 index 000000000..5a21b0a2e --- /dev/null +++ b/pkg/signature/profiles/applicationprofile_adapter.go @@ -0,0 +1,81 @@ +package profiles + +import ( + "github.com/kubescape/storage/pkg/apis/softwarecomposition/v1beta1" +) + +type ApplicationProfileAdapter struct { + profile *v1beta1.ApplicationProfile +} + +func NewApplicationProfileAdapter(profile *v1beta1.ApplicationProfile) *ApplicationProfileAdapter { + return &ApplicationProfileAdapter{ + profile: profile, + } +} + +func (a *ApplicationProfileAdapter) GetAnnotations() map[string]string { + if a.profile.Annotations == nil { + a.profile.Annotations = make(map[string]string) + } + return a.profile.Annotations +} + +func (a *ApplicationProfileAdapter) SetAnnotations(annotations map[string]string) { + a.profile.Annotations = annotations +} + +func (a *ApplicationProfileAdapter) GetUID() string { + return string(a.profile.UID) +} + +func (a *ApplicationProfileAdapter) GetNamespace() string { + return a.profile.Namespace +} + +func (a *ApplicationProfileAdapter) GetName() string { + return a.profile.Name +} + +func (a *ApplicationProfileAdapter) GetContent() interface{} { + // Normalize PolicyByRuleId to ensure consistent JSON representation + // Empty maps become {} instead of null + for i := range a.profile.Spec.Containers { + if a.profile.Spec.Containers[i].PolicyByRuleId == nil { + a.profile.Spec.Containers[i].PolicyByRuleId = make(map[string]v1beta1.RulePolicy) + } + } + for i := range a.profile.Spec.InitContainers { + if a.profile.Spec.InitContainers[i].PolicyByRuleId == nil { + a.profile.Spec.InitContainers[i].PolicyByRuleId = make(map[string]v1beta1.RulePolicy) + } + } + for i := range a.profile.Spec.EphemeralContainers { + if a.profile.Spec.EphemeralContainers[i].PolicyByRuleId == nil { + a.profile.Spec.EphemeralContainers[i].PolicyByRuleId = make(map[string]v1beta1.RulePolicy) + } + } + + apiVersion := a.profile.APIVersion + if apiVersion == "" { + apiVersion = "spdx.softwarecomposition.kubescape.io/v1beta1" + } + kind := a.profile.Kind + if kind == "" { + kind = "ApplicationProfile" + } + return map[string]interface{}{ + "apiVersion": apiVersion, + "kind": kind, + "metadata": map[string]interface{}{ + "name": a.profile.Name, + "namespace": a.profile.Namespace, + "labels": a.profile.Labels, + }, + "spec": a.profile.Spec, + } +} + +func (a *ApplicationProfileAdapter) GetUpdatedObject() interface{} { + return a.profile +} diff --git a/pkg/signature/profiles/empty_typemeta_test.go b/pkg/signature/profiles/empty_typemeta_test.go new file mode 100644 index 000000000..259ded5c7 --- /dev/null +++ b/pkg/signature/profiles/empty_typemeta_test.go @@ -0,0 +1,78 @@ +package profiles + +import ( + "testing" + + "github.com/kubescape/storage/pkg/apis/softwarecomposition/v1beta1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestApplicationProfileAdapterEmptyTypeMeta(t *testing.T) { + profile := &v1beta1.ApplicationProfile{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "", + Kind: "", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "test-ap", + Namespace: "default", + }, + Spec: v1beta1.ApplicationProfileSpec{ + Architectures: []string{"amd64"}, + }, + } + + adapter := NewApplicationProfileAdapter(profile) + + content := adapter.GetContent() + if content == nil { + t.Fatal("Expected non-nil content") + } + + apContent, ok := content.(map[string]interface{}) + if !ok { + t.Fatal("Expected map[string]interface{} content type") + } + + if apContent["apiVersion"] != "spdx.softwarecomposition.kubescape.io/v1beta1" { + t.Errorf("Expected fallback apiVersion 'spdx.softwarecomposition.kubescape.io/v1beta1', got '%v'", apContent["apiVersion"]) + } + + if apContent["kind"] != "ApplicationProfile" { + t.Errorf("Expected fallback kind 'ApplicationProfile', got '%v'", apContent["kind"]) + } +} + +func TestSeccompProfileAdapterEmptyTypeMeta(t *testing.T) { + profile := &v1beta1.SeccompProfile{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "", + Kind: "", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "test-seccomp", + Namespace: "default", + }, + Spec: v1beta1.SeccompProfileSpec{}, + } + + adapter := NewSeccompProfileAdapter(profile) + + content := adapter.GetContent() + if content == nil { + t.Fatal("Expected non-nil content") + } + + scContent, ok := content.(map[string]interface{}) + if !ok { + t.Fatal("Expected map[string]interface{} content type") + } + + if scContent["apiVersion"] != "spdx.softwarecomposition.kubescape.io/v1beta1" { + t.Errorf("Expected fallback apiVersion 'spdx.softwarecomposition.kubescape.io/v1beta1', got '%v'", scContent["apiVersion"]) + } + + if scContent["kind"] != "SeccompProfile" { + t.Errorf("Expected fallback kind 'SeccompProfile', got '%v'", scContent["kind"]) + } +} diff --git a/pkg/signature/profiles/networkneighborhood_adapter.go b/pkg/signature/profiles/networkneighborhood_adapter.go new file mode 100644 index 000000000..e62caf431 --- /dev/null +++ b/pkg/signature/profiles/networkneighborhood_adapter.go @@ -0,0 +1,63 @@ +package profiles + +import ( + "github.com/kubescape/storage/pkg/apis/softwarecomposition/v1beta1" +) + +type NetworkNeighborhoodAdapter struct { + nn *v1beta1.NetworkNeighborhood +} + +func NewNetworkNeighborhoodAdapter(nn *v1beta1.NetworkNeighborhood) *NetworkNeighborhoodAdapter { + return &NetworkNeighborhoodAdapter{ + nn: nn, + } +} + +func (a *NetworkNeighborhoodAdapter) GetAnnotations() map[string]string { + if a.nn.Annotations == nil { + a.nn.Annotations = make(map[string]string) + } + return a.nn.Annotations +} + +func (a *NetworkNeighborhoodAdapter) SetAnnotations(annotations map[string]string) { + a.nn.Annotations = annotations +} + +func (a *NetworkNeighborhoodAdapter) GetUID() string { + return string(a.nn.UID) +} + +func (a *NetworkNeighborhoodAdapter) GetNamespace() string { + return a.nn.Namespace +} + +func (a *NetworkNeighborhoodAdapter) GetName() string { + return a.nn.Name +} + +func (a *NetworkNeighborhoodAdapter) GetContent() interface{} { + apiVersion := a.nn.APIVersion + if apiVersion == "" { + apiVersion = "spdx.softwarecomposition.kubescape.io/v1beta1" + } + kind := a.nn.Kind + if kind == "" { + kind = "NetworkNeighborhood" + } + return map[string]interface{}{ + "apiVersion": apiVersion, + "kind": kind, + "metadata": map[string]interface{}{ + "name": a.nn.Name, + "namespace": a.nn.Namespace, + "labels": a.nn.Labels, + }, + "spec": a.nn.Spec, + } +} + +func (a *NetworkNeighborhoodAdapter) GetUpdatedObject() interface{} { + return a.nn +} diff --git a/pkg/signature/profiles/networkneighborhood_adapter_test.go b/pkg/signature/profiles/networkneighborhood_adapter_test.go new file mode 100644 index 000000000..7968784eb --- /dev/null +++ b/pkg/signature/profiles/networkneighborhood_adapter_test.go @@ -0,0 +1,99 @@ +package profiles + +import ( + "testing" + + "github.com/kubescape/storage/pkg/apis/softwarecomposition/v1beta1" + "github.com/stretchr/testify/assert" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestNetworkNeighborhoodAdapter(t *testing.T) { + nn := &v1beta1.NetworkNeighborhood{ + TypeMeta: metav1.TypeMeta{ + Kind: "NetworkNeighborhood", + APIVersion: "spdx.softwarecomposition.kubescape.io/v1beta1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "test-nn", + Namespace: "test-ns", + UID: "test-uid", + Annotations: map[string]string{ + "existing": "annotation", + }, + }, + Spec: v1beta1.NetworkNeighborhoodSpec{ + Containers: []v1beta1.NetworkNeighborhoodContainer{ + { + Name: "test-container", + Ingress: []v1beta1.NetworkNeighbor{ + { + Identifier: "test-neighbor", + }, + }, + }, + }, + }, + } + + adapter := NewNetworkNeighborhoodAdapter(nn) + + assert.Equal(t, "test-nn", adapter.GetName()) + assert.Equal(t, "test-ns", adapter.GetNamespace()) + assert.Equal(t, "test-uid", adapter.GetUID()) + + annotations := adapter.GetAnnotations() + assert.Equal(t, "annotation", annotations["existing"]) + + newAnnotations := map[string]string{"new": "annotation"} + adapter.SetAnnotations(newAnnotations) + assert.Equal(t, newAnnotations, nn.Annotations) + + content := adapter.GetContent().(map[string]interface{}) + assert.Equal(t, "NetworkNeighborhood", content["kind"]) + assert.Equal(t, "spdx.softwarecomposition.kubescape.io/v1beta1", content["apiVersion"]) + + metadata := content["metadata"].(map[string]interface{}) + assert.Equal(t, "test-nn", metadata["name"]) + assert.Equal(t, "test-ns", metadata["namespace"]) + + spec := content["spec"].(v1beta1.NetworkNeighborhoodSpec) + assert.Equal(t, 1, len(spec.Containers)) + assert.Equal(t, "test-container", spec.Containers[0].Name) + + assert.Equal(t, nn, adapter.GetUpdatedObject()) +} + +func TestNetworkNeighborhoodAdapter_EmptyTypeMeta(t *testing.T) { + nn := &v1beta1.NetworkNeighborhood{ + TypeMeta: metav1.TypeMeta{ + Kind: "", + APIVersion: "", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "test-nn", + Namespace: "test-ns", + }, + Spec: v1beta1.NetworkNeighborhoodSpec{ + Containers: []v1beta1.NetworkNeighborhoodContainer{ + { + Name: "test-container", + }, + }, + }, + } + + adapter := NewNetworkNeighborhoodAdapter(nn) + content := adapter.GetContent().(map[string]interface{}) + + assert.Equal(t, "NetworkNeighborhood", content["kind"]) + assert.Equal(t, "spdx.softwarecomposition.kubescape.io/v1beta1", content["apiVersion"]) + + metadata := content["metadata"].(map[string]interface{}) + assert.Equal(t, "test-nn", metadata["name"]) + assert.Equal(t, "test-ns", metadata["namespace"]) + + spec := content["spec"].(v1beta1.NetworkNeighborhoodSpec) + assert.Equal(t, 1, len(spec.Containers)) + assert.Equal(t, "test-container", spec.Containers[0].Name) +} diff --git a/pkg/signature/profiles/rules_adapter.go b/pkg/signature/profiles/rules_adapter.go new file mode 100644 index 000000000..248e3c1a9 --- /dev/null +++ b/pkg/signature/profiles/rules_adapter.go @@ -0,0 +1,60 @@ +package profiles + +import ( + rulemanagertypesv1 "github.com/kubescape/node-agent/pkg/rulemanager/types/v1" +) + +type RulesAdapter struct { + rules *rulemanagertypesv1.Rules +} + +func NewRulesAdapter(rules *rulemanagertypesv1.Rules) *RulesAdapter { + return &RulesAdapter{ + rules: rules, + } +} + +func (r *RulesAdapter) GetAnnotations() map[string]string { + return r.rules.Annotations +} + +func (r *RulesAdapter) SetAnnotations(annotations map[string]string) { + r.rules.Annotations = annotations +} + +func (r *RulesAdapter) GetUID() string { + return string(r.rules.UID) +} + +func (r *RulesAdapter) GetNamespace() string { + return r.rules.Namespace +} + +func (r *RulesAdapter) GetName() string { + return r.rules.Name +} + +func (r *RulesAdapter) GetContent() interface{} { + apiVersion := r.rules.APIVersion + if apiVersion == "" { + apiVersion = "kubescape.io/v1" + } + kind := r.rules.Kind + if kind == "" { + kind = "Rules" + } + return map[string]interface{}{ + "apiVersion": apiVersion, + "kind": kind, + "metadata": map[string]interface{}{ + "name": r.rules.Name, + "namespace": r.rules.Namespace, + "labels": r.rules.Labels, + }, + "spec": r.rules.Spec, + } +} + +func (r *RulesAdapter) GetUpdatedObject() interface{} { + return r.rules +} diff --git a/pkg/signature/profiles/rules_adapter_test.go b/pkg/signature/profiles/rules_adapter_test.go new file mode 100644 index 000000000..f617e4ebe --- /dev/null +++ b/pkg/signature/profiles/rules_adapter_test.go @@ -0,0 +1,184 @@ +package profiles + +import ( + "strings" + "testing" + + rulemanagertypesv1 "github.com/kubescape/node-agent/pkg/rulemanager/types/v1" + "github.com/kubescape/node-agent/pkg/signature" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + k8stypes "k8s.io/apimachinery/pkg/types" +) + +func TestRulesAdapterGetContent(t *testing.T) { + rules := &rulemanagertypesv1.Rules{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-rules", + Namespace: "default", + UID: k8stypes.UID("test-uid"), + Labels: map[string]string{"label": "value"}, + }, + Spec: rulemanagertypesv1.RulesSpec{ + Rules: []rulemanagertypesv1.Rule{ + { + Enabled: true, + ID: "rule-1", + Name: "Test Rule", + Description: "A test rule", + Expressions: rulemanagertypesv1.RuleExpressions{ + Message: "message", + UniqueID: "uniqueId", + RuleExpression: []rulemanagertypesv1.RuleExpression{}, + }, + ProfileDependency: 0, + Severity: 1, + SupportPolicy: false, + Tags: []string{"test"}, + }, + }, + }, + } + + adapter := NewRulesAdapter(rules) + content := adapter.GetContent() + + if content == nil { + t.Fatal("Expected content not to be nil") + } + + contentMap, ok := content.(map[string]interface{}) + if !ok { + t.Fatal("Expected content to be a map") + } + + if contentMap["apiVersion"] != "kubescape.io/v1" { + t.Errorf("Expected apiVersion 'kubescape.io/v1', got '%v'", contentMap["apiVersion"]) + } + + if contentMap["kind"] != "Rules" { + t.Errorf("Expected kind 'Rules', got '%v'", contentMap["kind"]) + } + + metadata, ok := contentMap["metadata"].(map[string]interface{}) + if !ok { + t.Fatal("Expected metadata to be a map") + } + + if metadata["name"] != "test-rules" { + t.Errorf("Expected name 'test-rules', got '%v'", metadata["name"]) + } + + if metadata["namespace"] != "default" { + t.Errorf("Expected namespace 'default', got '%v'", metadata["namespace"]) + } + + if _, ok := contentMap["spec"]; !ok { + t.Error("Expected spec in content") + } +} + +func TestRulesAdapterSignAndVerify(t *testing.T) { + rules := &rulemanagertypesv1.Rules{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "kubescape.io/v1", + Kind: "Rules", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "sign-test-rules", + Namespace: "default", + UID: k8stypes.UID("sign-rules-uid"), + Labels: map[string]string{ + "test": "rules-signing", + }, + }, + Spec: rulemanagertypesv1.RulesSpec{ + Rules: []rulemanagertypesv1.Rule{ + { + Enabled: true, + ID: "test-rule-id", + Name: "Test Rule", + Description: "A test rule", + Expressions: rulemanagertypesv1.RuleExpressions{ + Message: "message", + UniqueID: "uniqueId", + RuleExpression: []rulemanagertypesv1.RuleExpression{}, + }, + ProfileDependency: 0, + Severity: 1, + SupportPolicy: false, + Tags: []string{"test"}, + }, + }, + }, + } + + adapter := NewRulesAdapter(rules) + + err := signature.SignObjectDisableKeyless(adapter) + if err != nil { + t.Fatalf("SignObjectDisableKeyless failed: %v", err) + } + + if rules.Annotations == nil { + t.Error("Expected annotations to be set on rules") + } + + if _, ok := rules.Annotations[signature.AnnotationSignature]; !ok { + t.Error("Expected signature annotation on rules") + } + + err = signature.VerifyObjectAllowUntrusted(adapter) + if err != nil { + t.Fatalf("VerifyObjectAllowUntrusted failed: %v", err) + } +} + +func TestRulesAdapterSignAndVerifyWithTampering(t *testing.T) { + rules := &rulemanagertypesv1.Rules{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "kubescape.io/v1", + Kind: "Rules", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "tamper-test-rules", + Namespace: "default", + }, + Spec: rulemanagertypesv1.RulesSpec{ + Rules: []rulemanagertypesv1.Rule{ + { + Enabled: true, + ID: "tamper-rule-id", + Name: "Tamper Test Rule", + Description: "A tamper test rule", + Expressions: rulemanagertypesv1.RuleExpressions{ + Message: "message", + UniqueID: "uniqueId", + RuleExpression: []rulemanagertypesv1.RuleExpression{}, + }, + ProfileDependency: 0, + Severity: 1, + SupportPolicy: false, + Tags: []string{"test"}, + }, + }, + }, + } + + adapter := NewRulesAdapter(rules) + + err := signature.SignObjectDisableKeyless(adapter) + if err != nil { + t.Fatalf("SignObjectDisableKeyless failed: %v", err) + } + + rules.Spec.Rules[0].Name = "Modified Rule Name" + + err = signature.VerifyObjectAllowUntrusted(adapter) + if err == nil { + t.Fatal("Expected verification to fail after tampering, but it succeeded") + } + + if !strings.Contains(err.Error(), "signature verification failed") { + t.Errorf("Expected signature verification error, got: %v", err) + } +} diff --git a/pkg/signature/profiles/seccompprofile_adapter.go b/pkg/signature/profiles/seccompprofile_adapter.go new file mode 100644 index 000000000..8252cfbf7 --- /dev/null +++ b/pkg/signature/profiles/seccompprofile_adapter.go @@ -0,0 +1,63 @@ +package profiles + +import ( + "github.com/kubescape/storage/pkg/apis/softwarecomposition/v1beta1" +) + +type SeccompProfileAdapter struct { + profile *v1beta1.SeccompProfile +} + +func NewSeccompProfileAdapter(profile *v1beta1.SeccompProfile) *SeccompProfileAdapter { + return &SeccompProfileAdapter{ + profile: profile, + } +} + +func (s *SeccompProfileAdapter) GetAnnotations() map[string]string { + if s.profile.Annotations == nil { + s.profile.Annotations = make(map[string]string) + } + return s.profile.Annotations +} + +func (s *SeccompProfileAdapter) SetAnnotations(annotations map[string]string) { + s.profile.Annotations = annotations +} + +func (s *SeccompProfileAdapter) GetUID() string { + return string(s.profile.UID) +} + +func (s *SeccompProfileAdapter) GetNamespace() string { + return s.profile.Namespace +} + +func (s *SeccompProfileAdapter) GetName() string { + return s.profile.Name +} + +func (s *SeccompProfileAdapter) GetContent() interface{} { + apiVersion := s.profile.APIVersion + if apiVersion == "" { + apiVersion = "spdx.softwarecomposition.kubescape.io/v1beta1" + } + kind := s.profile.Kind + if kind == "" { + kind = "SeccompProfile" + } + return map[string]interface{}{ + "apiVersion": apiVersion, + "kind": kind, + "metadata": map[string]interface{}{ + "name": s.profile.Name, + "namespace": s.profile.Namespace, + "labels": s.profile.Labels, + }, + "spec": s.profile.Spec, + } +} + +func (s *SeccompProfileAdapter) GetUpdatedObject() interface{} { + return s.profile +} diff --git a/pkg/signature/sign.go b/pkg/signature/sign.go new file mode 100644 index 000000000..74ef6ba81 --- /dev/null +++ b/pkg/signature/sign.go @@ -0,0 +1,114 @@ +package signature + +import ( + "fmt" + + "github.com/kubescape/go-logger" + "github.com/kubescape/go-logger/helpers" +) + +func SignObject(obj SignableObject, opts ...SignOption) error { + if obj == nil { + return fmt.Errorf("object is nil") + } + options := &SignOptions{ + UseKeyless: true, + } + + for _, opt := range opts { + opt(options) + } + + var adapter *CosignAdapter + var err error + + if options.PrivateKey != nil { + adapter, err = NewCosignAdapterWithPrivateKey(false, options.PrivateKey) + } else { + adapter, err = NewCosignAdapter(options.UseKeyless) + } + + if err != nil { + return fmt.Errorf("failed to create cosign adapter: %w", err) + } + + content := obj.GetContent() + + hash, err := adapter.GetContentHash(content) + if err != nil { + return fmt.Errorf("failed to compute content hash: %w", err) + } + + logger.L().Debug("Signing object", + helpers.String("namespace", obj.GetNamespace()), + helpers.String("name", obj.GetName()), + helpers.String("contentHash", hash)) + + sig, err := adapter.SignData([]byte(hash)) + if err != nil { + return fmt.Errorf("failed to sign object: %w", err) + } + + annotations, err := adapter.EncodeSignatureToAnnotations(sig) + if err != nil { + return fmt.Errorf("failed to encode signature to annotations: %w", err) + } + + existingAnnotations := obj.GetAnnotations() + if existingAnnotations == nil { + existingAnnotations = make(map[string]string) + } + + for k, v := range annotations { + existingAnnotations[k] = v + } + + obj.SetAnnotations(existingAnnotations) + + logger.L().Info("Successfully signed object", + helpers.String("namespace", obj.GetNamespace()), + helpers.String("name", obj.GetName()), + helpers.String("identity", sig.Identity), + helpers.String("issuer", sig.Issuer)) + + return nil +} + +func SignObjectDisableKeyless(obj SignableObject) error { + return SignObject(obj, WithKeyless(false)) +} + +func SignObjectKeyless(obj SignableObject) error { + return SignObject(obj, WithKeyless(true)) +} + +func GetObjectSignature(obj SignableObject) (*Signature, error) { + if obj == nil { + return nil, fmt.Errorf("GetObjectSignature: nil object") + } + annotations := obj.GetAnnotations() + if annotations == nil { + return nil, fmt.Errorf("object has no annotations") + } + + adapter := &CosignAdapter{} + sig, err := adapter.DecodeSignatureFromAnnotations(annotations) + if err != nil { + return nil, fmt.Errorf("failed to decode signature from annotations: %w", err) + } + + return sig, nil +} + +func IsSigned(obj SignableObject) bool { + if obj == nil { + return false + } + annotations := obj.GetAnnotations() + if annotations == nil { + return false + } + + _, ok := annotations[AnnotationSignature] + return ok +} diff --git a/pkg/signature/sign_test.go b/pkg/signature/sign_test.go new file mode 100644 index 000000000..091484bce --- /dev/null +++ b/pkg/signature/sign_test.go @@ -0,0 +1,231 @@ +package signature + +import ( + "os" + "testing" +) + +type MockSignableObject struct { + annotations map[string]string + uid string + namespace string + name string + content interface{} +} + +func NewMockSignableObject(uid, namespace, name string, content interface{}) *MockSignableObject { + return &MockSignableObject{ + annotations: make(map[string]string), + uid: uid, + namespace: namespace, + name: name, + content: content, + } +} + +func (m *MockSignableObject) GetAnnotations() map[string]string { + return m.annotations +} + +func (m *MockSignableObject) SetAnnotations(annotations map[string]string) { + m.annotations = annotations +} + +func (m *MockSignableObject) GetUID() string { + return m.uid +} + +func (m *MockSignableObject) GetNamespace() string { + return m.namespace +} + +func (m *MockSignableObject) GetName() string { + return m.name +} + +func (m *MockSignableObject) GetContent() interface{} { + return m.content +} + +func (m *MockSignableObject) GetUpdatedObject() interface{} { + return m.content +} + +func TestSignObjectKeyless(t *testing.T) { + if os.Getenv("ENABLE_KEYLESS_TESTS") == "" { + t.Skip("Skipping TestSignObjectKeyless. Set ENABLE_KEYLESS_TESTS to run.") + } + profileContent := map[string]interface{}{ + "type": "test-profile", + "data": "test-data", + } + + profile := NewMockSignableObject("test-uid", "test-ns", "test-profile", profileContent) + + err := SignObjectKeyless(profile) + if err != nil { + t.Fatalf("SignObjectKeyless failed: %v", err) + } + + if !IsSigned(profile) { + t.Error("Profile should be signed") + } + + sig, err := GetObjectSignature(profile) + if err != nil { + t.Fatalf("GetObjectSignature failed: %v", err) + } + + if len(sig.Signature) == 0 { + t.Error("Signature should not be empty") + } + + if len(sig.Certificate) == 0 { + t.Error("Certificate should not be empty") + } + + if sig.Issuer == "" { + t.Error("Issuer should not be empty for keyless signing") + } + + if sig.Identity == "" { + t.Error("Identity should not be empty for keyless signing") + } +} + +func TestSignObjectDisableKeyless(t *testing.T) { + profileContent := map[string]interface{}{ + "type": "test-profile", + "data": "test-data", + } + + profile := NewMockSignableObject("test-uid", "test-ns", "test-profile-key", profileContent) + + err := SignObjectDisableKeyless(profile) + if err != nil { + t.Fatalf("SignObjectDisableKeyless failed: %v", err) + } + + if !IsSigned(profile) { + t.Error("Profile should be signed") + } + + sig, err := GetObjectSignature(profile) + if err != nil { + t.Fatalf("GetObjectSignature failed: %v", err) + } + + if len(sig.Signature) == 0 { + t.Error("Signature should not be empty") + } + + if sig.Issuer != "local" { + t.Errorf("Expected issuer 'local', got '%s'", sig.Issuer) + } + + if sig.Identity != "local-key" { + t.Errorf("Expected identity 'local-key', got '%s'", sig.Identity) + } +} + +func TestIsSigned(t *testing.T) { + tests := []struct { + name string + profile *MockSignableObject + expected bool + }{ + { + name: "Unsigned profile", + profile: NewMockSignableObject("uid", "ns", "name", map[string]string{}), + expected: false, + }, + { + name: "Profile with empty annotations", + profile: &MockSignableObject{annotations: make(map[string]string)}, + expected: false, + }, + { + name: "Profile with signature annotation", + profile: func() *MockSignableObject { + p := NewMockSignableObject("uid", "ns", "name", map[string]string{}) + p.SetAnnotations(map[string]string{ + AnnotationSignature: "test-sig", + }) + return p + }(), + expected: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := IsSigned(tt.profile) + if result != tt.expected { + t.Errorf("IsSigned() = %v, expected %v", result, tt.expected) + } + }) + } +} + +func TestGetObjectSignature(t *testing.T) { + tests := []struct { + name string + profile *MockSignableObject + wantErr bool + setupSign bool + setupAnnotations func(*MockSignableObject) + }{ + { + name: "Nil annotations", + profile: &MockSignableObject{uid: "uid", namespace: "ns", name: "name", content: map[string]string{}, annotations: nil}, + wantErr: true, + setupSign: false, + }, + { + name: "Missing signature annotation", + profile: NewMockSignableObject("uid", "ns", "name", map[string]string{}), + wantErr: true, + setupAnnotations: func(p *MockSignableObject) { + p.SetAnnotations(map[string]string{ + AnnotationIssuer: "test-issuer", + }) + }, + }, + { + name: "Complete signature", + profile: NewMockSignableObject("uid", "ns", "name", map[string]string{}), + wantErr: false, + setupSign: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.setupSign { + if os.Getenv("ENABLE_KEYLESS_TESTS") == "" { + t.Skip("Skipping subtest with SignObjectKeyless. Set ENABLE_KEYLESS_TESTS to run.") + } + SignObjectKeyless(tt.profile) + } else if tt.setupAnnotations != nil { + tt.setupAnnotations(tt.profile) + } + + sig, err := GetObjectSignature(tt.profile) + + if tt.wantErr { + if err == nil { + t.Error("Expected error, got nil") + } + return + } + + if err != nil { + t.Fatalf("GetObjectSignature failed: %v", err) + } + + if sig == nil { + t.Fatal("Expected signature, got nil") + } + }) + } +} diff --git a/pkg/signature/signer.go b/pkg/signature/signer.go new file mode 100644 index 000000000..8f3197bd9 --- /dev/null +++ b/pkg/signature/signer.go @@ -0,0 +1,20 @@ +package signature + +type CosignSigner struct { + adapter *CosignAdapter +} + +func NewCosignSigner(useKeyless bool) (*CosignSigner, error) { + adapter, err := NewCosignAdapter(useKeyless) + if err != nil { + return nil, err + } + + return &CosignSigner{ + adapter: adapter, + }, nil +} + +func (s *CosignSigner) Sign(data []byte) (*Signature, error) { + return s.adapter.SignData(data) +} diff --git a/pkg/signature/verifier.go b/pkg/signature/verifier.go new file mode 100644 index 000000000..4278757cb --- /dev/null +++ b/pkg/signature/verifier.go @@ -0,0 +1,38 @@ +package signature + +import "fmt" + +type CosignVerifier struct { + adapter *CosignAdapter +} + +func NewCosignVerifier(useKeyless bool) (*CosignVerifier, error) { + adapter, err := NewCosignAdapter(useKeyless) + if err != nil { + return nil, err + } + + return &CosignVerifier{ + adapter: adapter, + }, nil +} + +func (v *CosignVerifier) Verify(data []byte, sig *Signature) error { + if v == nil || v.adapter == nil { + return fmt.Errorf("verifier not initialized") + } + if sig == nil { + return fmt.Errorf("signature is nil") + } + return v.adapter.VerifyData(data, sig, false) +} + +func (v *CosignVerifier) VerifyAllowUntrusted(data []byte, sig *Signature) error { + if v == nil || v.adapter == nil { + return fmt.Errorf("verifier not initialized") + } + if sig == nil { + return fmt.Errorf("signature is nil") + } + return v.adapter.VerifyData(data, sig, true) +} diff --git a/pkg/signature/verify.go b/pkg/signature/verify.go new file mode 100644 index 000000000..f5d3d9913 --- /dev/null +++ b/pkg/signature/verify.go @@ -0,0 +1,85 @@ +package signature + +import ( + "fmt" + + "github.com/kubescape/go-logger" + "github.com/kubescape/go-logger/helpers" +) + +func VerifyObject(obj SignableObject, opts ...VerifyOption) error { + if obj == nil { + return fmt.Errorf("object is nil") + } + options := &VerifyOptions{ + AllowUntrusted: false, + } + + for _, opt := range opts { + opt(options) + } + + annotations := obj.GetAnnotations() + if annotations == nil { + return fmt.Errorf("%w (missing %s annotation)", ErrObjectNotSigned, AnnotationSignature) + } + + if _, ok := annotations[AnnotationSignature]; !ok { + return fmt.Errorf("%w (missing %s annotation)", ErrObjectNotSigned, AnnotationSignature) + } + + // useKeyless=true is fine for verification since we use the certificate + // stored in the object annotations, regardless of how the object was signed + adapter, err := NewCosignAdapter(true) + if err != nil { + return fmt.Errorf("failed to create cosign adapter: %w", err) + } + + sig, err := adapter.DecodeSignatureFromAnnotations(annotations) + if err != nil { + return fmt.Errorf("failed to decode signature from annotations: %w", err) + } + + content := obj.GetContent() + hash, err := adapter.GetContentHash(content) + if err != nil { + return fmt.Errorf("failed to compute content hash: %w", err) + } + + verifier, err := NewCosignVerifier(true) + if err != nil { + return fmt.Errorf("failed to create verifier: %w", err) + } + + var verifyErr error + if options.AllowUntrusted { + verifyErr = verifier.VerifyAllowUntrusted([]byte(hash), sig) + } else { + verifyErr = verifier.Verify([]byte(hash), sig) + } + + if verifyErr != nil { + logger.L().Warning("Object signature verification failed", + helpers.String("namespace", obj.GetNamespace()), + helpers.String("name", obj.GetName()), + helpers.String("error", verifyErr.Error())) + + return fmt.Errorf("signature verification failed: %w", verifyErr) + } + + logger.L().Info("Successfully verified object signature", + helpers.String("namespace", obj.GetNamespace()), + helpers.String("name", obj.GetName()), + helpers.String("identity", sig.Identity), + helpers.String("issuer", sig.Issuer)) + + return nil +} + +func VerifyObjectStrict(obj SignableObject) error { + return VerifyObject(obj, WithUntrusted(false)) +} + +func VerifyObjectAllowUntrusted(obj SignableObject) error { + return VerifyObject(obj, WithUntrusted(true)) +} diff --git a/pkg/signature/verify_test.go b/pkg/signature/verify_test.go new file mode 100644 index 000000000..1e76336f5 --- /dev/null +++ b/pkg/signature/verify_test.go @@ -0,0 +1,199 @@ +package signature + +import ( + "os" + "testing" +) + +func TestVerifyObjectStrict(t *testing.T) { + if os.Getenv("ENABLE_KEYLESS_TESTS") == "" { + t.Skip("Skipping TestVerifyObjectStrict. Set ENABLE_KEYLESS_TESTS to run.") + } + profileContent := map[string]interface{}{ + "type": "test-profile", + "data": "test-data", + "value": 123, + } + + profile := NewMockSignableObject("test-uid", "test-ns", "test-profile-verify", profileContent) + + err := SignObjectKeyless(profile) + if err != nil { + t.Fatalf("SignObjectKeyless failed: %v", err) + } + + err = VerifyObjectStrict(profile) + if err != nil { + t.Fatalf("VerifyObjectStrict failed: %v", err) + } +} + +func TestVerifyObjectAllowUntrusted(t *testing.T) { + profileContent := map[string]interface{}{ + "type": "test-profile", + "data": "test-data", + "value": 456, + } + + profile := NewMockSignableObject("test-uid", "test-ns", "test-profile-verify-2", profileContent) + + err := SignObjectDisableKeyless(profile) + if err != nil { + t.Fatalf("SignObjectDisableKeyless failed: %v", err) + } + + err = VerifyObjectAllowUntrusted(profile) + if err != nil { + t.Fatalf("VerifyObjectAllowUntrusted failed: %v", err) + } +} + +func TestVerifyObjectTampered(t *testing.T) { + if os.Getenv("ENABLE_KEYLESS_TESTS") == "" { + t.Skip("Skipping TestVerifyObjectTampered. Set ENABLE_KEYLESS_TESTS to run.") + } + originalContent := map[string]interface{}{ + "type": "test-profile", + "data": "test-data", + "value": 789, + "confident": "secret", + } + + profile := NewMockSignableObject("test-uid", "test-ns", "test-profile-tamper", originalContent) + + err := SignObjectKeyless(profile) + if err != nil { + t.Fatalf("SignObjectKeyless failed: %v", err) + } + + tamperedContent := map[string]interface{}{ + "type": "test-profile", + "data": "test-data", + "value": 999, + "confident": "mod", + } + profile.content = tamperedContent + + err = VerifyObjectStrict(profile) + if err == nil { + t.Error("Expected verification failure for tampered profile, got success") + } +} + +func TestVerifyObjectNoAnnotations(t *testing.T) { + profileContent := map[string]interface{}{ + "type": "test-profile", + "data": "test-data", + } + + profile := NewMockSignableObject("test-uid", "test-ns", "test-profile-no-sig", profileContent) + + err := VerifyObjectStrict(profile) + if err == nil { + t.Error("Expected error for profile without annotations, got nil") + } +} + +func TestVerifyObjectMissingSignature(t *testing.T) { + profileContent := map[string]interface{}{ + "type": "test-profile", + "data": "test-data", + } + + profile := NewMockSignableObject("test-uid", "test-ns", "test-profile-missing-sig", profileContent) + profile.SetAnnotations(map[string]string{ + AnnotationIssuer: "test-issuer", + AnnotationIdentity: "test-identity", + }) + + err := VerifyObjectStrict(profile) + if err == nil { + t.Error("Expected error for profile without signature annotation, got nil") + } +} + +func TestSignAndVerifyRoundTrip(t *testing.T) { + if os.Getenv("ENABLE_KEYLESS_TESTS") == "" { + t.Skip("Skipping TestSignAndVerifyRoundTrip. Set ENABLE_KEYLESS_TESTS to run.") + } + profileContent := map[string]interface{}{ + "type": "roundtrip-profile", + "containers": []string{"nginx", "redis"}, + "capabilities": []string{"NET_BIND_SERVICE"}, + "networkPolicy": "allow", + } + + profile := NewMockSignableObject("roundtrip-uid", "roundtrip-ns", "roundtrip-profile", profileContent) + + err := SignObjectKeyless(profile) + if err != nil { + t.Fatalf("SignObjectKeyless failed: %v", err) + } + + if !IsSigned(profile) { + t.Fatal("Profile should be signed after signing") + } + + sig, err := GetObjectSignature(profile) + if err != nil { + t.Fatalf("GetObjectSignature failed: %v", err) + } + + if len(sig.Signature) == 0 { + t.Error("Signature should not be empty") + } + + err = VerifyObjectStrict(profile) + if err != nil { + t.Fatalf("VerifyObjectStrict failed after signing: %v", err) + } +} + +func TestSignAndVerifyDifferentKeys(t *testing.T) { + if os.Getenv("ENABLE_KEYLESS_TESTS") == "" { + t.Skip("Skipping TestSignAndVerifyDifferentKeys. Set ENABLE_KEYLESS_TESTS to run.") + } + profileContent := map[string]interface{}{ + "type": "multi-key-test", + "data": "data", + } + + profile1 := NewMockSignableObject("uid1", "ns", "profile1", profileContent) + profile2 := NewMockSignableObject("uid2", "ns", "profile2", profileContent) + + err := SignObjectDisableKeyless(profile1) + if err != nil { + t.Fatalf("SignObjectDisableKeyless failed for profile1: %v", err) + } + + err = SignObjectKeyless(profile2) + if err != nil { + t.Fatalf("SignObjectKeyless failed for profile2: %v", err) + } + + sig1, err := GetObjectSignature(profile1) + if err != nil { + t.Fatalf("GetObjectSignature failed for profile1: %v", err) + } + + sig2, err := GetObjectSignature(profile2) + if err != nil { + t.Fatalf("GetObjectSignature failed for profile2: %v", err) + } + + if sig1.Issuer != "local" { + t.Errorf("Expected key-based signing issuer 'local', got '%s'", sig1.Issuer) + } + + if sig1.Identity != "local-key" { + t.Errorf("Expected key-based signing identity 'local-key', got '%s'", sig1.Identity) + } + + if sig2.Issuer == "" { + t.Errorf("Expected keyless signing to have issuer, got empty") + } + + if sig2.Identity == "" { + t.Errorf("Expected keyless signing to have identity, got empty") + } +}