diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml new file mode 100644 index 00000000..b0ab2f6a --- /dev/null +++ b/.github/workflows/integration-test.yml @@ -0,0 +1,26 @@ +name: Integration Tests + +on: + workflow_dispatch: # Manual trigger only + push: + +jobs: + integration-test: + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - name: Checkout code + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 + + - name: Set up Go + uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 + with: + go-version: 1.24.2 + cache: true + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 + + - name: Run integration tests + run: make integration-tests diff --git a/Makefile b/Makefile index 82983fca..1204ccbf 100644 --- a/Makefile +++ b/Makefile @@ -27,8 +27,11 @@ SOURCE ?= TAG ?= LICENSE ?= +# Test configuration +BUILD_DMR ?= 1 + # Main targets -.PHONY: build run clean test docker-build docker-build-multiplatform docker-run docker-build-vllm docker-run-vllm docker-run-impl help validate model-distribution-tool +.PHONY: build run clean test integration-tests docker-build docker-build-multiplatform docker-run docker-build-vllm docker-run-vllm docker-run-impl help validate model-distribution-tool # Default target .DEFAULT_GOAL := build @@ -60,6 +63,19 @@ clean: test: go test -v ./... +integration-tests: + @echo "Running integration tests..." + @echo "Note: This requires Docker to be running" + @echo "Checking test naming conventions..." + @INVALID_TESTS=$$(grep "^func Test" cmd/cli/commands/integration_test.go | grep -v "^func TestIntegration"); \ + if [ -n "$$INVALID_TESTS" ]; then \ + echo "Error: Found test functions that don't start with 'TestIntegration':"; \ + echo "$$INVALID_TESTS" | sed 's/func \([^(]*\).*/\1/'; \ + exit 1; \ + fi + @BUILD_DMR=$(BUILD_DMR) go test -v -race -count=1 -tags=integration -run "^TestIntegration" -timeout=5m ./cmd/cli/commands + @echo "Integration tests completed!" + validate: find . -type f -name "*.sh" | xargs shellcheck diff --git a/cmd/cli/commands/integration_test.go b/cmd/cli/commands/integration_test.go new file mode 100644 index 00000000..8b7e8c87 --- /dev/null +++ b/cmd/cli/commands/integration_test.go @@ -0,0 +1,464 @@ +//go:build integration + +package commands + +import ( + "context" + "fmt" + "io" + "net/url" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" + "time" + + "github.com/docker/model-runner/cmd/cli/desktop" + "github.com/docker/model-runner/pkg/distribution/builder" + "github.com/docker/model-runner/pkg/distribution/registry" + "github.com/stretchr/testify/require" + "github.com/testcontainers/testcontainers-go" + tc "github.com/testcontainers/testcontainers-go/modules/registry" + "github.com/testcontainers/testcontainers-go/network" + "github.com/testcontainers/testcontainers-go/wait" +) + +// testEnv holds the test environment components +type testEnv struct { + ctx context.Context + registryURL string + client *desktop.Client +} + +// modelInfo contains all the information needed to generate model references +type modelInfo struct { + name string // e.g., "test-model" + org string // e.g., "ai" + tag string // e.g., "latest" + registry string // e.g., "registry.local:5000" + modelID string // Full ID: sha256:... + digest string // sha256:... + expectedName string // What we expect to see: "ai/test-model:latest" +} + +// referenceTestCase represents a test case for a specific reference format +type referenceTestCase struct { + name string + ref string +} + +// generateReferenceTestCases generates a comprehensive list of reference formats for testing +func generateReferenceTestCases(info modelInfo) []referenceTestCase { + cases := []referenceTestCase{ + { + name: "short form (no registry, no org, no tag)", + ref: info.name, + }, + { + name: "with tag", + ref: fmt.Sprintf("%s:%s", info.name, info.tag), + }, + { + name: "with org", + ref: fmt.Sprintf("%s/%s", info.org, info.name), + }, + { + name: "with org and tag", + ref: fmt.Sprintf("%s/%s:%s", info.org, info.name, info.tag), + }, + { + name: "fqdn", + ref: fmt.Sprintf("%s/%s/%s:%s", info.registry, info.org, info.name, info.tag), + }, + { + name: "with registry and org", + ref: fmt.Sprintf("%s/%s/%s", info.registry, info.org, info.name), + }, + { + name: "by digest", + ref: fmt.Sprintf("%s@%s", info.name, info.digest), + }, + { + name: "by digest with org", + ref: fmt.Sprintf("%s/%s@%s", info.org, info.name, info.digest), + }, + { + name: "by digest with registry and org", + ref: fmt.Sprintf("%s/%s/%s@%s", info.registry, info.org, info.name, info.digest), + }, + { + name: "full model ID", + ref: info.modelID, + }, + { + name: "truncated model ID (12 chars)", + ref: info.modelID[7:19], + }, + { + name: "model ID without sha256 prefix", + ref: strings.TrimPrefix(info.modelID, "sha256:"), + }, + } + + return cases +} + +// setupTestEnv creates the complete test environment with registry and DMR +func setupTestEnv(t *testing.T) *testEnv { + ctx := context.Background() + + // Create a custom network for container communication + net, err := network.New(ctx) + require.NoError(t, err) + testcontainers.CleanupNetwork(t, net) + + registryURL := ociRegistry(t, ctx, net) + dmrURL := dockerModelRunner(t, ctx, net) + + modelRunnerCtx, err := desktop.NewContextForTest(dmrURL, nil) + require.NoError(t, err, "Failed to create model runner context") + + client := desktop.New(modelRunnerCtx) + if !client.Status().Running { + t.Fatal("DMR is not running") + } + + return &testEnv{ + ctx: ctx, + registryURL: registryURL, + client: client, + } +} + +func ociRegistry(t *testing.T, ctx context.Context, net *testcontainers.DockerNetwork) string { + t.Log("Starting OCI registry container...") + ctr, err := tc.Run(context.Background(), "registry:3", + network.WithNetwork([]string{"registry.local"}, net), + ) + require.NoError(t, err) + testcontainers.CleanupContainer(t, ctr) + + registryEndpoint, err := ctr.Endpoint(ctx, "") + require.NoError(t, err) + registryURL := fmt.Sprintf("http://%s", registryEndpoint) + t.Logf("Registry available at: %s", registryURL) + return registryURL +} + +func dockerModelRunner(t *testing.T, ctx context.Context, net *testcontainers.DockerNetwork) string { + containerCustomizerOpts := []testcontainers.ContainerCustomizer{ + testcontainers.WithExposedPorts("12434/tcp"), + testcontainers.WithWaitStrategy(wait.ForHTTP("/engines/status").WithPort("12434/tcp").WithStartupTimeout(10 * time.Second)), + testcontainers.WithEnv(map[string]string{ + "DEFAULT_REGISTRY": "registry.local:5000", + "INSECURE_REGISTRY": "true", + }), + network.WithNetwork([]string{"dmr"}, net), + } + if os.Getenv("BUILD_DMR") == "1" { + t.Log("Building DMR container...") + out, err := exec.CommandContext(ctx, "make", "-C", "../../..", "docker-build").CombinedOutput() + if err != nil { + t.Fatalf("Failed to build DMR container: %v\n%s", err, out) + } + } else { + // Always pull the image if it's not build locally. + containerCustomizerOpts = append(containerCustomizerOpts, testcontainers.WithAlwaysPull()) + } + t.Log("Starting DMR container...") + ctr, err := testcontainers.Run( + ctx, "docker/model-runner:latest", + containerCustomizerOpts..., + ) + require.NoError(t, err) + testcontainers.CleanupContainer(t, ctr) + + dmrEndpoint, err := ctr.Endpoint(ctx, "") + require.NoError(t, err) + + dmrURL := fmt.Sprintf("http://%s", dmrEndpoint) + t.Logf("DMR available at: %s", dmrURL) + return dmrURL +} + +// removeModel removes a model from the local store +func removeModel(client *desktop.Client, modelID string) error { + _, err := client.Remove([]string{modelID}, true) + return err +} + +// verifyModelInspect inspects a model using the given reference and verifies it matches expectations +func verifyModelInspect(t *testing.T, client *desktop.Client, ref, expectedID, expectedDigest string) { + t.Helper() + + model, err := client.Inspect(ref, false) + require.NoError(t, err, "Failed to inspect model with reference: %s", ref) + + // Verify model ID matches + require.Equal(t, expectedID, model.ID, + "Model ID mismatch when inspecting with reference: %s. Expected: %s, Got: %s", + ref, expectedID, model.ID) + + // Verify digest matches + require.Equal(t, expectedDigest, model.ID, + "Model digest mismatch when inspecting with reference: %s. Expected: %s, Got: %s", + ref, expectedDigest, model.ID) + + // Verify model has tags + require.NotEmpty(t, model.Tags, "Model should have at least one tag") + + t.Logf("✓ Successfully inspected model with reference: %s (ID: %s, Tags: %v)", + ref, model.ID[7:19], model.Tags) +} + +// createAndPushTestModel creates a minimal test model and pushes it to the local registry. +// Returns the model ID, FQDNs for host and network access, and the manifest digest. +func createAndPushTestModel(t *testing.T, registryURL, modelRef string, contextSize uint64) (modelID, hostFQDN, networkFQDN, digest string) { + ctx := context.Background() + + // Use the dummy GGUF file from assets + dummyGGUFPath := filepath.Join("../../../assets/dummy.gguf") + absPath, err := filepath.Abs(dummyGGUFPath) + require.NoError(t, err) + + // Check if the file exists + _, err = os.Stat(absPath) + require.NoError(t, err, "dummy.gguf not found at %s", absPath) + + // Create a builder from the GGUF file + t.Logf("Creating test model %s from %s", modelRef, absPath) + pkg, err := builder.FromGGUF(absPath) + require.NoError(t, err) + + // Set context size if specified + if contextSize > 0 { + pkg = pkg.WithContextSize(contextSize) + } + + // Construct the full reference with the local registry host for pushing from test host + uri, err := url.Parse(registryURL) + require.NoError(t, err) + + hostFQDN = fmt.Sprintf("%s/%s", uri.Host, modelRef) + t.Logf("Pushing to local registry: %s", hostFQDN) + + // Create registry client + client := registry.NewClient(registry.WithUserAgent("integration-test/1.0")) + target, err := client.NewTarget(hostFQDN) + require.NoError(t, err) + + // Push the model + err = pkg.Build(ctx, target, io.Discard) + require.NoError(t, err) + t.Logf("Successfully pushed test model: %s", hostFQDN) + + // For pulling from DMR, use the network alias "registry.local:5000" + // go-containerregistry will automatically use HTTP for .local hostnames + networkFQDN = fmt.Sprintf("registry.local:5000/%s", modelRef) + + id, err := pkg.Model().ID() + require.NoError(t, err) + t.Logf("Model ID: %s", id) + + // Get the manifest digest + manifestDigest, err := pkg.Model().Digest() + require.NoError(t, err) + digest = manifestDigest.String() + t.Logf("Model digest: %s", digest) + + return id, hostFQDN, networkFQDN, digest +} + +// TestIntegration_PullModel tests pulling a model from the local OCI registry via DMR +// with various model reference formats to ensure proper normalization. +func TestIntegration_PullModel(t *testing.T) { + env := setupTestEnv(t) + + models, err := listModels(false, env.client, true, false, "") + require.NoError(t, err) + + if len(models) != 0 { + t.Fatal("Expected no initial models, but found some") + } + + // Create and push two test models with different organizations + // Model 1: custom org (test/test-model:latest) + modelRef1 := "test/test-model:latest" + modelID1, hostFQDN1, networkFQDN1, digest1 := createAndPushTestModel(t, env.registryURL, modelRef1, 2048) + t.Logf("Test model 1 pushed: %s (ID: %s) FQDN: %s Digest: %s", hostFQDN1, modelID1, networkFQDN1, digest1) + + // Generate test cases for custom org model (test/test-model) + customOrgInfo := modelInfo{ + name: "test-model", + org: "test", + tag: "latest", + registry: "registry.local:5000", + modelID: modelID1, + digest: digest1, + expectedName: "test/test-model:latest", + } + customOrgCases := generateReferenceTestCases(customOrgInfo) + + // Model 2: default org (ai/test-model:latest) + modelRef2 := "ai/test-model:latest" + modelID2, hostFQDN2, networkFQDN2, digest2 := createAndPushTestModel(t, env.registryURL, modelRef2, 2048) + t.Logf("Test model 2 pushed: %s (ID: %s) FQDN: %s Digest: %s", hostFQDN2, modelID2, networkFQDN2, digest2) + + // Generate test cases for default org model (ai/test-model) + defaultOrgInfo := modelInfo{ + name: "test-model", + org: "ai", + tag: "latest", + registry: "registry.local:5000", + modelID: modelID2, + digest: digest2, + expectedName: "ai/test-model:latest", + } + defaultOrgCases := generateReferenceTestCases(defaultOrgInfo) + + // Combine test cases with expected model IDs + // References without explicit org should resolve to ai/ (default org) + // References with explicit "test" org should resolve to test/test-model + type pullTestCase struct { + referenceTestCase + expectedModelID string + expectedModelName string + expectedDigest string + } + + var testCases []pullTestCase + + // Add custom org cases (with explicit "test" org in reference) + // Only include cases where the reference explicitly contains the "test" org + // Cases without explicit org will normalize to "ai/" (default org) + for _, tc := range customOrgCases { + // Skip ID-based references for pull tests (can't pull by ID) + if strings.Contains(tc.name, "model ID") { + continue + } + // Skip cases that don't have explicit org in the reference + // These will normalize to the default org (ai/) and should only be in defaultOrgCases + if !strings.Contains(tc.ref, "test/") && !strings.Contains(tc.ref, "registry.local:5000/test/") { + continue + } + testCases = append(testCases, pullTestCase{ + referenceTestCase: tc, + expectedModelID: modelID1, + expectedModelName: "test/test-model:latest", + expectedDigest: digest1, + }) + } + + // Add default org cases (references that should default to ai/) + for _, tc := range defaultOrgCases { + // Skip ID-based references for pull tests (can't pull by ID) + if strings.Contains(tc.name, "model ID") { + continue + } + testCases = append(testCases, pullTestCase{ + referenceTestCase: tc, + expectedModelID: modelID2, + expectedModelName: "ai/test-model:latest", + expectedDigest: digest2, + }) + } + + // Run all test cases + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Pull the model using the test case reference + t.Logf("Pulling model with reference: %s", tc.ref) + err := pullModel(newPullCmd(), env.client, tc.ref, true) + require.NoError(t, err, "Failed to pull model with reference: %s", tc.ref) + + // List models and verify the expected model is present + models, err := listModels(false, env.client, true, false, "") + require.NoError(t, err) + + if len(models) == 0 { + t.Fatalf("No models found after pulling %s", tc.ref) + } + + models = strings.TrimSpace(models) + + // Extract truncated ID format (sha256:xxx... -> xxx where xxx is 12 chars) + // listModels with quiet=true returns modelID[7:19] + truncatedID := tc.expectedModelID[7:19] + if models != truncatedID { + t.Errorf("Expected model ID %s (truncated: %s) not found in model list after pulling %s.\nExpected model: %s\nModel list:\n%s", + tc.expectedModelID, truncatedID, tc.ref, tc.expectedModelName, models) + } else { + t.Logf("✓ Successfully verified model %s (ID: %s) after pulling with reference: %s", + tc.expectedModelName, truncatedID, tc.ref) + } + + // Verify inspect works with the same reference used for pulling + verifyModelInspect(t, env.client, tc.ref, tc.expectedModelID, tc.expectedDigest) + + // Clean up: remove the model for the next test iteration + t.Logf("Removing model %s", truncatedID) + err = removeModel(env.client, tc.expectedModelID) + require.NoError(t, err, "Failed to remove model") + }) + } +} + +// TestIntegration_InspectModel tests inspecting a model with various reference formats +// to ensure proper reference normalization and consistent output. +func TestIntegration_InspectModel(t *testing.T) { + env := setupTestEnv(t) + + // Ensure no models exist initially + models, err := listModels(false, env.client, true, false, "") + require.NoError(t, err) + if len(models) != 0 { + t.Fatal("Expected no initial models, but found some") + } + + // Create and push a test model with default org (ai/inspect-test:latest) + modelRef := "ai/inspect-test:latest" + modelID, hostFQDN, networkFQDN, digest := createAndPushTestModel(t, env.registryURL, modelRef, 2048) + t.Logf("Test model pushed: %s (ID: %s) FQDN: %s Digest: %s", hostFQDN, modelID, networkFQDN, digest) + + // Pull the model using a short reference + pullRef := "inspect-test" + t.Logf("Pulling model with reference: %s", pullRef) + err = pullModel(newPullCmd(), env.client, pullRef, true) + require.NoError(t, err, "Failed to pull model") + + // Verify the model was pulled + models, err = listModels(false, env.client, true, false, "") + require.NoError(t, err) + truncatedID := modelID[7:19] + require.Equal(t, truncatedID, strings.TrimSpace(models), "Model not found after pull") + + // Generate all reference test cases using the unified system + info := modelInfo{ + name: "inspect-test", + org: "ai", + tag: "latest", + registry: "registry.local:5000", + modelID: modelID, + digest: digest, + expectedName: "ai/inspect-test:latest", + } + testCases := generateReferenceTestCases(info) + + // Verify inspect works with all reference formats + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + verifyModelInspect(t, env.client, tc.ref, modelID, digest) + }) + } + + // Cleanup: remove the model + t.Logf("Removing model %s", truncatedID) + err = removeModel(env.client, modelID) + require.NoError(t, err, "Failed to remove model") + + // Verify model was removed + models, err = listModels(false, env.client, true, false, "") + require.NoError(t, err) + require.Empty(t, strings.TrimSpace(models), "Model should be removed") +} diff --git a/cmd/cli/desktop/context.go b/cmd/cli/desktop/context.go index d3ff0c5b..e0caf147 100644 --- a/cmd/cli/desktop/context.go +++ b/cmd/cli/desktop/context.go @@ -105,6 +105,26 @@ func NewContextForMock(client DockerHttpClient) *ModelRunnerContext { } } +// NewContextForTest creates a ModelRunnerContext for integration testing +// with a custom URL endpoint. This is intended for use in integration tests +// where the Model Runner endpoint is dynamically created (e.g., testcontainers). +func NewContextForTest(endpoint string, client DockerHttpClient) (*ModelRunnerContext, error) { + urlPrefix, err := url.Parse(endpoint) + if err != nil { + return nil, fmt.Errorf("invalid endpoint URL: %w", err) + } + + if client == nil { + client = http.DefaultClient + } + + return &ModelRunnerContext{ + kind: types.ModelRunnerEngineKindMoby, + urlPrefix: urlPrefix, + client: client, + }, nil +} + // DetectContext determines the current Docker Model Runner context. func DetectContext(ctx context.Context, cli *command.DockerCli) (*ModelRunnerContext, error) { // Check for an explicit endpoint setting. diff --git a/cmd/cli/desktop/desktop.go b/cmd/cli/desktop/desktop.go index 0c2e08d9..fc8ac8fa 100644 --- a/cmd/cli/desktop/desktop.go +++ b/cmd/cli/desktop/desktop.go @@ -257,7 +257,13 @@ func (c *Client) ListOpenAI() (dmrm.OpenAIModelList, error) { func (c *Client) Inspect(model string, remote bool) (dmrm.Model, error) { model = normalizeHuggingFaceModelName(model) if model != "" { - if !strings.Contains(strings.Trim(model, "/"), "/") { + // Only try to expand to model ID if the reference doesn't contain: + // - A slash (org/name format) + // - A colon (tagged reference like name:tag) + // - An @ symbol (digest reference like name@sha256:...) + if !strings.Contains(strings.Trim(model, "/"), "/") && + !strings.Contains(model, ":") && + !strings.Contains(model, "@") { // Do an extra API call to check if the model parameter isn't a model ID. modelId, err := c.fullModelID(model) if err != nil { diff --git a/cmd/cli/go.mod b/cmd/cli/go.mod index c2eb1bc2..0f06bc22 100644 --- a/cmd/cli/go.mod +++ b/cmd/cli/go.mod @@ -7,8 +7,8 @@ require ( github.com/containerd/errdefs v1.0.0 github.com/docker/cli v28.3.0+incompatible github.com/docker/cli-docs-tool v0.10.0 - github.com/docker/docker v28.2.2+incompatible - github.com/docker/go-connections v0.5.0 + github.com/docker/docker v28.3.3+incompatible + github.com/docker/go-connections v0.6.0 github.com/docker/go-units v0.5.0 github.com/docker/model-runner v0.0.0 github.com/emirpasic/gods/v2 v2.0.0-alpha @@ -23,6 +23,8 @@ require ( github.com/spf13/cobra v1.10.1 github.com/spf13/pflag v1.0.9 github.com/stretchr/testify v1.11.1 + github.com/testcontainers/testcontainers-go v0.39.0 + github.com/testcontainers/testcontainers-go/modules/registry v0.39.0 go.opentelemetry.io/otel v1.37.0 go.uber.org/mock v0.5.0 golang.org/x/sync v0.17.0 @@ -31,6 +33,7 @@ require ( ) require ( + dario.cat/mergo v1.0.2 // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/alecthomas/chroma/v2 v2.14.0 // indirect @@ -49,6 +52,7 @@ require ( github.com/containerd/platforms v1.0.0-rc.1 // indirect github.com/containerd/stargz-snapshotter/estargz v0.16.3 // indirect github.com/containerd/typeurl/v2 v2.2.3 // indirect + github.com/cpuguy83/dockercfg v0.3.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect github.com/creack/pty v1.1.24 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect @@ -56,6 +60,7 @@ require ( github.com/dlclark/regexp2 v1.11.0 // indirect github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/docker-credential-helpers v0.9.3 // indirect + github.com/ebitengine/purego v0.8.4 // indirect github.com/elastic/go-sysinfo v1.15.4 // indirect github.com/elastic/go-windows v1.0.2 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect @@ -78,14 +83,20 @@ require ( github.com/klauspost/compress v1.18.0 // indirect github.com/kolesnikovae/go-winjob v1.0.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/magiconair/properties v1.8.10 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-shellwords v1.0.12 // indirect github.com/microcosm-cc/bluemonday v1.0.27 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect + github.com/moby/go-archive v0.1.0 // indirect github.com/moby/locker v1.0.1 // indirect + github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/atomicwriter v0.1.0 // indirect github.com/moby/sys/sequential v0.6.0 // indirect + github.com/moby/sys/user v0.4.0 // indirect + github.com/moby/sys/userns v0.1.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/morikuni/aec v1.0.0 // indirect @@ -95,14 +106,18 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.1 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/shirou/gopsutil/v4 v4.25.6 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smallnest/ringbuffer v0.0.0-20241116012123-461381446e3d // indirect github.com/theupdateframework/notary v0.7.1-0.20210315103452-bf96a202a09a // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect github.com/vbatts/tar-split v0.12.1 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect github.com/yuin/goldmark v1.7.8 // indirect diff --git a/cmd/cli/go.sum b/cmd/cli/go.sum index 9bb5d886..e64bd9d5 100644 --- a/cmd/cli/go.sum +++ b/cmd/cli/go.sum @@ -1,3 +1,5 @@ +dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= +dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk= github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= @@ -69,6 +71,8 @@ github.com/containerd/stargz-snapshotter/estargz v0.16.3 h1:7evrXtoh1mSbGj/pfRcc github.com/containerd/stargz-snapshotter/estargz v0.16.3/go.mod h1:uyr4BfYfOj3G9WBVE8cOlQmXAbPN9VEQpBBeJIuOipU= github.com/containerd/typeurl/v2 v2.2.3 h1:yNA/94zxWdvYACdYO8zofhrTVuQY73fFU1y++dYSw40= github.com/containerd/typeurl/v2 v2.2.3/go.mod h1:95ljDnPfD3bAbDJRugOiShd/DlAAsxGtUBhJxIn7SCk= +github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= +github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= @@ -91,15 +95,15 @@ github.com/docker/cli-docs-tool v0.10.0/go.mod h1:5EM5zPnT2E7yCLERZmrDA234Vwn09f github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v28.2.2+incompatible h1:CjwRSksz8Yo4+RmQ339Dp/D2tGO5JxwYeqtMOEe0LDw= -github.com/docker/docker v28.2.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v28.3.3+incompatible h1:Dypm25kh4rmk49v1eiVbsAtpAsYURjYkaKubwuBdxEI= +github.com/docker/docker v28.3.3+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/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0= github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c/go.mod h1:CADgU4DSXK5QUlFslkQu2yW2TKzFZcXq/leZfM0UH5Q= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= -github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= +github.com/docker/go-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-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= @@ -109,6 +113,8 @@ github.com/docker/go-winjob v0.0.0-20250829235554-57b487ebcbc5 h1:dxSFEb0EEmvceI github.com/docker/go-winjob v0.0.0-20250829235554-57b487ebcbc5/go.mod h1:ICOGmIXdwhfid7rQP+tLvDJqVg0lHdEk3pI5nsapTtg= github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/dvsekhvalnov/jose2go v0.0.0-20170216131308-f21a8cedbbae/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM= +github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw= +github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/elastic/go-sysinfo v1.15.4 h1:A3zQcunCxik14MgXu39cXFXcIw2sFXZ0zL886eyiv1Q= github.com/elastic/go-sysinfo v1.15.4/go.mod h1:ZBVXmqS368dOn/jvijV/zHLfakWTYHBZPk3G244lHrU= github.com/elastic/go-windows v1.0.2 h1:yoLLsAsV5cfg9FLhZ9EXZ2n2sQFKeDYrHenkcivY4vI= @@ -146,6 +152,7 @@ github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaW github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/certificate-transparency-go v1.0.10-0.20180222191210-5ab67e519c93/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-containerregistry v0.20.6 h1:cvWX87UxxLgaH76b4hIvya6Dzz9qHB31qAwjAohdSTU= @@ -196,7 +203,11 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.5.3/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= +github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -220,14 +231,20 @@ github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk github.com/mitchellh/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ= +github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo= github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= +github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= +github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw= github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs= github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg= github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4= github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= +github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs= +github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= @@ -265,6 +282,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_golang v0.9.0-pre1.0.20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= @@ -285,6 +304,8 @@ github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shirou/gopsutil/v4 v4.25.6 h1:kLysI2JsKorfaFPcYmcJqbzROzsBWEOAtw6A7dIfqXs= +github.com/shirou/gopsutil/v4 v4.25.6/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c= github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= @@ -311,8 +332,16 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/testcontainers/testcontainers-go v0.39.0 h1:uCUJ5tA+fcxbFAB0uP3pIK3EJ2IjjDUHFSZ1H1UxAts= +github.com/testcontainers/testcontainers-go v0.39.0/go.mod h1:qmHpkG7H5uPf/EvOORKvS6EuDkBUPE3zpVGaH9NL7f8= +github.com/testcontainers/testcontainers-go/modules/registry v0.39.0 h1:Wq08A4G5o/OYb68xWVzVWSHrpckpYab4+5u+8T5UaYQ= +github.com/testcontainers/testcontainers-go/modules/registry v0.39.0/go.mod h1:RIRXImSUJ5MYAiM8Hl39JdMD6pHsRsgfhgR+L22dhMk= github.com/theupdateframework/notary v0.7.1-0.20210315103452-bf96a202a09a h1:tlJ7tGUHvcvL1v3yR6NcCc9nOqh2L+CG6HWrYQtwzQ0= github.com/theupdateframework/notary v0.7.1-0.20210315103452-bf96a202a09a/go.mod h1:Y94A6rPp2OwNfP/7vmf8O2xx2IykP8pPXQ1DLouGnEw= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/vbatts/tar-split v0.12.1 h1:CqKoORW7BUWBe7UL/iqTVvkTBOF8UvOMKOIZykxnnbo= github.com/vbatts/tar-split v0.12.1/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= @@ -393,11 +422,14 @@ golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7w 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-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= diff --git a/go.work.sum b/go.work.sum index 08b981d8..497ba02f 100644 --- a/go.work.sum +++ b/go.work.sum @@ -133,6 +133,7 @@ github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8 github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/danieljoos/wincred v1.2.2 h1:774zMFJrqaeYCK2W57BgAem/MLi6mtSE47MB6BOJ0i0= github.com/danieljoos/wincred v1.2.2/go.mod h1:w7w4Utbrz8lqeMbDAK0lkNJUv5sAOkFi7nd/ogr0Uh8= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= @@ -348,12 +349,14 @@ github.com/mndrix/tap-go v0.0.0-20171203230836-629fa407e90b h1:Ga1nclDSe8gOw37MV github.com/mndrix/tap-go v0.0.0-20171203230836-629fa407e90b/go.mod h1:pzzDgJWZ34fGzaAZGFW22KVZDfyrYW+QABMrWnJBnSs= github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU= github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= +github.com/moby/sys/mount v0.3.4 h1:yn5jq4STPztkkzSKpZkLcmjue+bZJ0u2AuQY1iNI1Ww= +github.com/moby/sys/mount v0.3.4/go.mod h1:KcQJMbQdJHPlq5lcYT+/CjatWM4PuxKe+XLSVS4J6Os= +github.com/moby/sys/reexec v0.1.0 h1:RrBi8e0EBTLEgfruBOFcxtElzRGTEUkeIFaVXgU7wok= +github.com/moby/sys/reexec v0.1.0/go.mod h1:EqjBg8F3X7iZe5pU6nRZnYCMUTXoxsjiIfHup5wYIN8= github.com/moby/sys/signal v0.7.1 h1:PrQxdvxcGijdo6UXXo/lU/TvHUWyPhj7UOpSo8tuvk0= github.com/moby/sys/signal v0.7.1/go.mod h1:Se1VGehYokAkrSQwL4tDzHvETwUZlnY7S5XtQ50mQp8= github.com/moby/sys/symlink v0.3.0 h1:GZX89mEZ9u53f97npBy4Rc3vJKj7JBDj/PN2I22GrNU= github.com/moby/sys/symlink v0.3.0/go.mod h1:3eNdhduHmYPcgsJtZXW1W4XUJdZGBIkttZ8xKqPUJq0= -github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs= -github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mrunalp/fileutils v0.5.0 h1:NKzVxiH7eSk+OQ4M+ZYW1K6h27RUV3MI6NUTsHhU6Z4= @@ -374,6 +377,8 @@ github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y= github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= github.com/open-policy-agent/opa v0.70.0 h1:B3cqCN2iQAyKxK6+GI+N40uqkin+wzIrM7YA60t9x1U= github.com/open-policy-agent/opa v0.70.0/go.mod h1:Y/nm5NY0BX0BqjBriKUiV81sCl8XOjjvqQG7dXrggtI= +github.com/openai/openai-go v0.1.0-beta.9 h1:ABpubc5yU/3ejee2GgRrbFta81SG/d7bQbB8mIdP0Xo= +github.com/openai/openai-go v0.1.0-beta.9/go.mod h1:g461MYGXEXBVdV5SaR/5tNzNbSfwTBBefwc+LlDCK0Y= github.com/opencontainers/runc v1.2.3 h1:fxE7amCzfZflJO2lHXf4y/y8M1BoAqp+FVmG19oYB80= github.com/opencontainers/runc v1.2.3/go.mod h1:nSxcWUydXrsBZVYNSkTjoQ/N6rcyTtn+1SD5D4+kRIM= github.com/opencontainers/runtime-spec v1.0.3-0.20220825212826-86290f6a00fb/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= @@ -398,6 +403,8 @@ github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFu github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A= 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/pkoukk/tiktoken-go v0.1.6 h1:JF0TlJzhTbrI30wCvFuiw6FzP2+/bR+FIxUdgEAcUsw= +github.com/pkoukk/tiktoken-go v0.1.6/go.mod h1:9NiV+i9mJKGj1rYOT+njbv+ZwA/zJxYdewGl6qVatpg= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/pquerna/cachecontrol v0.1.0 h1:yJMy84ti9h/+OEWa752kBTKv4XC30OtVVHYv/8cTqKc= @@ -460,8 +467,18 @@ github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtse github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tchap/go-patricia/v2 v2.3.2 h1:xTHFutuitO2zqKAQ5rCROYgUb7Or/+IC3fts9/Yc7nM= github.com/tchap/go-patricia/v2 v2.3.2/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k= +github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= +github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= +github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE= github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk= +github.com/tmc/langchaingo v0.1.13 h1:rcpMWBIi2y3B90XxfE4Ao8dhCQPVDMaNPnN5cGB1CaA= +github.com/tmc/langchaingo v0.1.13/go.mod h1:vpQ5NOIhpzxDfTZK9B6tf2GM/MoaHewPWM5KXXGh7hg= github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 h1:pyC9PaHYZFgEKFdlp3G8RaCKgVpHZnecvArXvPXcFkM= github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA= github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc= @@ -612,7 +629,6 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/pkg/distribution/internal/store/index.go b/pkg/distribution/internal/store/index.go index 692fd442..7f4a9357 100644 --- a/pkg/distribution/internal/store/index.go +++ b/pkg/distribution/internal/store/index.go @@ -6,6 +6,7 @@ import ( "fmt" "os" "path/filepath" + "strings" "github.com/google/go-containerregistry/pkg/name" @@ -18,6 +19,12 @@ type Index struct { } func (i Index) Tag(reference string, tag string) (Index, error) { + // Remove @sha256 in case the reference is a digest + tag = strings.TrimSpace(tag) + if idx := strings.Index(tag, "@sha256"); idx != -1 { + tag = tag[:idx] + } + tag = strings.TrimPrefix(tag, reference) tagRef, err := name.NewTag(tag, registry.GetDefaultRegistryOptions()...) if err != nil { return Index{}, fmt.Errorf("invalid tag: %w", err)