diff --git a/apt_test.go b/apt_test.go index f64cac194..09fb43e6e 100644 --- a/apt_test.go +++ b/apt_test.go @@ -15,6 +15,9 @@ import ( "testing" "time" + buildinfo "github.com/jfrog/build-info-go/entities" + "github.com/jfrog/jfrog-cli-core/v2/common/build" + "github.com/jfrog/jfrog-cli/inttestutils" "github.com/jfrog/jfrog-cli/utils/tests" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -552,7 +555,7 @@ func TestAptInstall_TrustedFlag(t *testing.T) { runJfrogCli(t, "apt", "install", "--dry-run", "-y", "curl", "--repo="+aptRepo(), - "--dist=noble", + "--dist="+testDist(), "--trusted", ) @@ -617,6 +620,439 @@ func TestAptSetupThenNativeInstall(t *testing.T) { assertPersistentInstallFromArtifactory(t, "curl", *tests.JfrogUrl) } +// ── auth + setup with existing virtual repo ─────────────────────────────────── + +// TestAptInstall_PersistentSetupJfAptInstall verifies the "setup once, then +// jf apt install without flags" flow against the pre-configured virtual repository +// (cli-apt-virtual, backed by ubuntu-remote + debian-remote + local members). +// +// After `jf setup apt` writes a persistent sources.list with embedded credentials +// and a Pin-Priority: 1001 preferences file, a bare `jf apt install` (no --repo / +// --dist) must detect the persistent config, route the install through Artifactory, +// and succeed. +func TestAptInstall_PersistentSetupJfAptInstall(t *testing.T) { + initAptTest(t) + requireRoot(t) + defer cleanAptTest(t) + + repo := aptRepo() + dist := testDist() + const pkg = "ed" + + if out, err := exec.Command("apt-get", "purge", "-y", pkg).CombinedOutput(); err != nil { + t.Logf("pre-test purge of %s skipped: %v\n%s", pkg, err, out) + } + + // Write persistent sources.list + pinning file for the shared virtual repo. + runJfrogCli(t, "setup", "apt", + "--repo="+repo, + "--dist="+dist, + "--component=main", + "--trusted", + ) + + require.FileExists(t, sourcesListPath(repo, dist)) + require.FileExists(t, prefPath(repo, dist)) + + // Install WITHOUT --repo/--dist. Must log "Using persistent Artifactory apt + // configuration" and proxy the install through the configured virtual repo. + runJfrogCli(t, "apt", "install", "-y", pkg) + + _, err := exec.LookPath(pkg) + assert.NoError(t, err, "%s must be installed via persistent-config 'jf apt install'", pkg) + assertPersistentInstallFromArtifactory(t, pkg, *tests.JfrogUrl) +} + +// TestAptInstall_BuildInfoWithVirtualRepo verifies end-to-end build-info collection +// against the pre-configured virtual repository (cli-apt-virtual). +// +// Flow: +// 1. jf apt install curl with --build-name/--build-number; build-info is saved locally. +// 2. Local build-info is validated: module type debian, deps type deb, SHA256 present. +// 3. jf rt bp publishes the build-info to Artifactory. +// 4. The published build-info is fetched and round-trip-validated. +func TestAptInstall_BuildInfoWithVirtualRepo(t *testing.T) { + initAptTest(t) + requireRoot(t) + defer cleanAptTest(t) + defer inttestutils.DeleteBuild(serverDetails.ArtifactoryUrl, tests.AptBuildName, artHttpDetails) + + repo := aptRepo() + dist := testDist() + const buildNumber = "1" + // curl: in the "main" component on every matrix dist (focal→trixie), served by the + // ubuntu/debian remotes in the virtual repo, and pulls a non-base dependency + // (libcurl4/libcurl4t64) that resolves with a checksum from the Packages index — + // so build-info always has at least one checksummed dependency. (jq is in + // "universe" on focal, so it cannot be used across the whole matrix.) + const pkg = "curl" + + if out, err := exec.Command("apt-get", "purge", "-y", pkg).CombinedOutput(); err != nil { + t.Logf("pre-test purge of %s skipped: %v\n%s", pkg, err, out) + } + + runJfrogCli(t, "apt", "install", "-y", "--allow-downgrades", pkg, + "--repo="+repo, + "--dist="+dist, + "--trusted", + "--build-name="+tests.AptBuildName, + "--build-number="+buildNumber, + ) + + _, err := exec.LookPath(pkg) + require.NoError(t, err, "%s must be installed after jf apt install", pkg) + + // Validate the locally persisted build-info before it is published. + validateAptLocalBuildInfo(t, tests.AptBuildName, buildNumber) + + // Publish and validate the round-trip through Artifactory. + runJfrogCli(t, "rt", "bp", tests.AptBuildName, buildNumber) + + publishedBuildInfo, found, err := tests.GetBuildInfo(serverDetails, tests.AptBuildName, buildNumber) + require.NoError(t, err) + require.True(t, found, "build %s/%s must appear in Artifactory after bp", tests.AptBuildName, buildNumber) + + bi := publishedBuildInfo.BuildInfo + require.Len(t, bi.Modules, 1, "apt build-info must have exactly one module") + mod := bi.Modules[0] + assert.Equal(t, string(buildinfo.Debian), string(mod.Type)) + assert.NotEmpty(t, mod.Dependencies, "apt build-info must have at least one dependency") + for _, dep := range mod.Dependencies { + assert.Equal(t, "deb", dep.Type, "dep %s must have type deb", dep.Id) + assert.NotEmpty(t, dep.Sha256, "dep %s must have SHA256 checksum", dep.Id) + } +} + +// validateAptLocalBuildInfo validates the build-info persisted locally after +// `jf apt install --build-name/--build-number` before it is published to Artifactory. +func validateAptLocalBuildInfo(t *testing.T, buildName, buildNumber string) { + t.Helper() + buildInfoService := build.CreateBuildInfoService() + aptBuild, err := buildInfoService.GetOrCreateBuildWithProject(buildName, buildNumber, "") + require.NoError(t, err) + bi, err := aptBuild.ToBuildInfo() + require.NoError(t, err) + require.NotEmpty(t, bi.Started) + if !assert.Len(t, bi.Modules, 1, "apt build-info must have exactly one module") { + return + } + mod := bi.Modules[0] + assert.Equal(t, string(buildinfo.Debian), string(mod.Type)) + assert.NotEmpty(t, mod.Dependencies, "apt build-info must have at least one dependency") + for _, dep := range mod.Dependencies { + assert.Equal(t, "deb", dep.Type, "dep %s must have type deb", dep.Id) + assert.NotEmpty(t, dep.Sha256, "dep %s must have SHA256 checksum", dep.Id) + assert.NotEmpty(t, dep.Scopes, "dep %s must have at least one scope", dep.Id) + } +} + +// ── build info dep properties ───────────────────────────────────────────────── + +// TestAptInstall_BuildInfoDepProperties verifies scenarios #42–#45: +// - #42: dependency ID format is name:version:arch +// - #43: Depends/Pre-Depends → required, Recommends → recommended +// - #44: sha256/sha1/md5 populated from Packages index +// - #45: requestedBy chains are acyclic (no package in its own ancestry) +func TestAptInstall_BuildInfoDepProperties(t *testing.T) { + initAptTest(t) + requireRoot(t) + defer cleanAptTest(t) + defer func() { _ = build.RemoveBuildDir(tests.AptBuildName, "2", "") }() + + if out, err := exec.Command("apt-get", "purge", "-y", "curl").CombinedOutput(); err != nil { + t.Logf("purge curl: %v\n%s", err, out) + } + + runJfrogCli(t, "apt", "install", "-y", "--allow-downgrades", "curl", + "--repo="+aptRepo(), + "--dist="+testDist(), + "--trusted", + "--build-name="+tests.AptBuildName, + "--build-number=2", + ) + + buildInfoService := build.CreateBuildInfoService() + aptBuild, err := buildInfoService.GetOrCreateBuildWithProject(tests.AptBuildName, "2", "") + require.NoError(t, err) + bi, err := aptBuild.ToBuildInfo() + require.NoError(t, err) + require.Len(t, bi.Modules, 1) + + for _, dep := range bi.Modules[0].Dependencies { + // #42: ID must be name:version:arch + parts := strings.SplitN(dep.Id, ":", 3) + assert.Len(t, parts, 3, "dep %s: ID must be name:version:arch", dep.Id) + assert.NotEmpty(t, parts[0], "dep %s: name must not be empty", dep.Id) + assert.NotEmpty(t, parts[1], "dep %s: version must not be empty", dep.Id) + assert.NotEmpty(t, parts[2], "dep %s: arch must not be empty", dep.Id) + + // type must be deb + assert.Equal(t, "deb", dep.Type, "dep %s: type must be deb", dep.Id) + + // #43: scope must be one of the three valid values + for _, scope := range dep.Scopes { + assert.Contains(t, []string{"required", "recommended", "optional"}, scope, + "dep %s: unexpected scope %q", dep.Id, scope) + } + + // #44: sha256 must be populated + assert.NotEmpty(t, dep.Sha256, "dep %s: sha256 must be populated", dep.Id) + + // #45: package must not appear in its own requestedBy ancestry + for _, path := range dep.RequestedBy { + assert.NotContains(t, path, dep.Id, + "dep %s must not appear in its own requestedBy chain: %v", dep.Id, path) + } + } +} + +// ── build info flag combinations ────────────────────────────────────────────── + +// TestAptInstall_BuildModule verifies scenario #35: --module overrides module ID. +func TestAptInstall_BuildModule(t *testing.T) { + initAptTest(t) + requireRoot(t) + defer cleanAptTest(t) + defer func() { _ = build.RemoveBuildDir(tests.AptBuildName, "3", "") }() + + const moduleID = "my-custom-apt-module" + + if out, err := exec.Command("apt-get", "purge", "-y", "curl").CombinedOutput(); err != nil { + t.Logf("purge curl: %v\n%s", err, out) + } + + runJfrogCli(t, "apt", "install", "-y", "--allow-downgrades", "curl", + "--repo="+aptRepo(), + "--dist="+testDist(), + "--trusted", + "--build-name="+tests.AptBuildName, + "--build-number=3", + "--module="+moduleID, + ) + + buildInfoService := build.CreateBuildInfoService() + aptBuild, err := buildInfoService.GetOrCreateBuildWithProject(tests.AptBuildName, "3", "") + require.NoError(t, err) + bi, err := aptBuild.ToBuildInfo() + require.NoError(t, err) + require.Len(t, bi.Modules, 1) + assert.Equal(t, moduleID, bi.Modules[0].Id, "--module must override the default module ID") +} + +// TestAptInstall_BuildNameOnlyError verifies scenario #36: +// --build-name without --build-number → CLI rejects the partial flags with an error. +// JFrog CLI enforces that both flags must be provided together; a partial pair is +// an error rather than silently skipping build info collection. +func TestAptInstall_BuildNameOnlyError(t *testing.T) { + initAptTest(t) + defer cleanAptTest(t) + + err := runJfrogCliWithoutAssertion("apt", "install", "--dry-run", "-y", "curl", + "--repo="+aptRepo(), + "--dist="+testDist(), + "--trusted", + "--build-name=cli-apt-nameonly-test", + // no --build-number + ) + assert.Error(t, err, "--build-name without --build-number must return an error") +} + +// TestAptInstall_BuildNumberOnlyError verifies scenario #37: +// --build-number without --build-name → CLI rejects with an error. +func TestAptInstall_BuildNumberOnlyError(t *testing.T) { + initAptTest(t) + defer cleanAptTest(t) + + err := runJfrogCliWithoutAssertion("apt", "install", "--dry-run", "-y", "curl", + "--repo="+aptRepo(), + "--dist="+testDist(), + "--trusted", + "--build-number=1", + // no --build-name + ) + assert.Error(t, err, "--build-number without --build-name must return an error") +} + +// TestAptInstall_NoBuildFlagsNoBuildInfo verifies scenario #38: +// no build flags → install succeeds, no build info produced. +func TestAptInstall_NoBuildFlagsNoBuildInfo(t *testing.T) { + initAptTest(t) + requireRoot(t) + defer cleanAptTest(t) + + const buildName = "cli-apt-nobuild-test" + const buildNum = "1" + + runJfrogCli(t, "apt", "install", "--dry-run", "-y", "curl", + "--repo="+aptRepo(), + "--dist="+testDist(), + "--trusted", + // no --build-name, no --build-number + ) + + buildInfoService := build.CreateBuildInfoService() + aptBuild, err := buildInfoService.GetOrCreateBuildWithProject(buildName, buildNum, "") + require.NoError(t, err) + bi, err := aptBuild.ToBuildInfo() + require.NoError(t, err) + assert.Empty(t, bi.Modules, "no build flags must not produce build info") +} + +// TestAptInstall_BuildFlagsFromEnvVars verifies scenario #39: +// JFROG_CLI_BUILD_NAME + JFROG_CLI_BUILD_NUMBER env vars → build info captured. +func TestAptInstall_BuildFlagsFromEnvVars(t *testing.T) { + initAptTest(t) + requireRoot(t) + defer cleanAptTest(t) + defer func() { _ = build.RemoveBuildDir(tests.AptBuildName, "4", "") }() + + t.Setenv("JFROG_CLI_BUILD_NAME", tests.AptBuildName) + t.Setenv("JFROG_CLI_BUILD_NUMBER", "4") + + if out, err := exec.Command("apt-get", "purge", "-y", "curl").CombinedOutput(); err != nil { + t.Logf("purge curl: %v\n%s", err, out) + } + + // No --build-name / --build-number flags; env vars must supply them. + runJfrogCli(t, "apt", "install", "-y", "--allow-downgrades", "curl", + "--repo="+aptRepo(), + "--dist="+testDist(), + "--trusted", + ) + + buildInfoService := build.CreateBuildInfoService() + aptBuild, err := buildInfoService.GetOrCreateBuildWithProject(tests.AptBuildName, "4", "") + require.NoError(t, err) + bi, err := aptBuild.ToBuildInfo() + require.NoError(t, err) + require.Len(t, bi.Modules, 1, "build info must be captured from env vars") + assert.NotEmpty(t, bi.Modules[0].Dependencies) +} + +// ── dispatch ────────────────────────────────────────────────────────────────── + +// TestAptInstall_DpkgQueryDispatch verifies scenario #29: +// jf apt dpkg-query dispatches to dpkg-query without auth injection. +func TestAptInstall_DpkgQueryDispatch(t *testing.T) { + initAptTest(t) + defer cleanAptTest(t) + + // base-files is always installed; dpkg-query must find it. + runJfrogCli(t, "apt", "dpkg-query", "-W", + "-f=${Package}\\t${Version}\\n", "base-files") +} + +// ── closure bounded ─────────────────────────────────────────────────────────── + +// TestAptInstall_ClosureBounded verifies scenario #71: +// apt-cache closure is bounded to installed packages via --installed --no-suggests. +// curl's full archive closure is ~23,000 packages; with bounding it is <20. +func TestAptInstall_ClosureBounded(t *testing.T) { + initAptTest(t) + requireRoot(t) + defer cleanAptTest(t) + defer func() { _ = build.RemoveBuildDir(tests.AptBuildName, "5", "") }() + + if out, err := exec.Command("apt-get", "purge", "-y", "curl").CombinedOutput(); err != nil { + t.Logf("purge curl: %v\n%s", err, out) + } + + runJfrogCli(t, "apt", "install", "-y", "--allow-downgrades", "curl", + "--repo="+aptRepo(), + "--dist="+testDist(), + "--trusted", + "--build-name="+tests.AptBuildName, + "--build-number=5", + ) + + buildInfoService := build.CreateBuildInfoService() + aptBuild, err := buildInfoService.GetOrCreateBuildWithProject(tests.AptBuildName, "5", "") + require.NoError(t, err) + bi, err := aptBuild.ToBuildInfo() + require.NoError(t, err) + require.Len(t, bi.Modules, 1) + + depCount := len(bi.Modules[0].Dependencies) + // With --installed --no-suggests the closure is bounded to packages already on + // the system; without these flags apt-cache walks the whole archive (~23,000 + // packages). The exact count varies by distro (Ubuntu noble: ~4, Debian + // bookworm: ~40); the important invariant is it stays well under 200. + assert.Less(t, depCount, 200, + "curl dep count %d exceeds expected bound; --installed --no-suggests must be active", depCount) + assert.Greater(t, depCount, 0, "curl must have at least one dependency") +} + +// ── Artifactory unreachable ─────────────────────────────────────────────────── + +// TestAptInstall_ArtifactoryUnreachable verifies scenario #66: +// on-the-fly install against a nonexistent repo returns a clear error; +// apt must not silently fall back to system sources (Dir::Etc::sourceparts=-). +func TestAptInstall_ArtifactoryUnreachable(t *testing.T) { + initAptTest(t) + requireRoot(t) + defer cleanAptTest(t) + + err := runJfrogCliWithoutAssertion("apt", "install", "-y", "curl", + "--repo=repo-does-not-exist-xyz-abc", + "--dist="+testDist(), + "--trusted", + ) + require.Error(t, err, + "install against nonexistent repo must fail (no silent fallback to system sources)") +} + +// ── full CI pipeline ───────────────────────────────────────────────────────── + +// TestAptInstall_FullPipeline verifies scenario #65: +// jf setup apt → jf apt install with build flags → jf rt bp → build in Artifactory. +func TestAptInstall_FullPipeline(t *testing.T) { + initAptTest(t) + requireRoot(t) + defer cleanAptTest(t) + defer inttestutils.DeleteBuild(serverDetails.ArtifactoryUrl, tests.AptBuildName, artHttpDetails) + + const buildNumber = "6" + // curl is in "main" on every matrix dist (jq is in "universe" on focal). + const pkg = "curl" + dist := testDist() + + // 1. Persistent setup against the shared virtual repo. + runJfrogCli(t, "setup", "apt", + "--repo="+aptRepo(), + "--dist="+dist, + "--component=main", + "--trusted", + ) + require.FileExists(t, sourcesListPath(aptRepo(), dist)) + + if out, err := exec.Command("apt-get", "purge", "-y", pkg).CombinedOutput(); err != nil { + t.Logf("purge %s: %v\n%s", pkg, err, out) + } + + // 2. Install using persistent config (no --repo/--dist needed). + runJfrogCli(t, "apt", "install", "-y", "--allow-downgrades", pkg, + "--build-name="+tests.AptBuildName, + "--build-number="+buildNumber, + ) + + _, err := exec.LookPath(pkg) + require.NoError(t, err, "%s must be installed", pkg) + + // 3. Validate local build info. + validateAptLocalBuildInfo(t, tests.AptBuildName, buildNumber) + + // 4. Publish to Artifactory. + runJfrogCli(t, "rt", "bp", tests.AptBuildName, buildNumber) + + // 5. Verify round-trip. + publishedBuildInfo, found, err := tests.GetBuildInfo(serverDetails, tests.AptBuildName, buildNumber) + require.NoError(t, err) + require.True(t, found, "build info must be in Artifactory after jf rt bp") + require.Len(t, publishedBuildInfo.BuildInfo.Modules, 1) + assert.Equal(t, string(buildinfo.Debian), string(publishedBuildInfo.BuildInfo.Modules[0].Type)) + assert.NotEmpty(t, publishedBuildInfo.BuildInfo.Modules[0].Dependencies) +} + // ── distribution matrix ─────────────────────────────────────────────────────── // TestAptSetup_DistributionMatrix runs setup across multiple dist values. diff --git a/buildtools/cli.go b/buildtools/cli.go index 5194f77f8..50ccaab20 100644 --- a/buildtools/cli.go +++ b/buildtools/cli.go @@ -14,6 +14,7 @@ import ( alpinecommand "github.com/jfrog/jfrog-cli-artifactory/artifactory/commands/alpine" aptcommand "github.com/jfrog/jfrog-cli-artifactory/artifactory/commands/apt" cargocommand "github.com/jfrog/jfrog-cli-artifactory/artifactory/commands/cargo" + aptflex "github.com/jfrog/build-info-go/flexpack/apt" conancommand "github.com/jfrog/jfrog-cli-artifactory/artifactory/commands/conan" nixcommand "github.com/jfrog/jfrog-cli-artifactory/artifactory/commands/nix" rubycommandexec "github.com/jfrog/jfrog-cli-artifactory/artifactory/commands/ruby" @@ -2360,9 +2361,20 @@ func AptCmd(c *cli.Context) error { if err != nil { return err } - // Strip build flags so they aren't passed through to apt-get. Build-info - // collection is out of scope for the auth flow. - filteredArgs, _, err := build.ExtractBuildDetailsFromArgs(args) + args, fromFile, err := coreutils.ExtractStringOptionFromArgs(args, "from-file") + if err != nil { + return err + } + // Expand --from-file: inject package names after the "install" subcommand. + if fromFile != "" { + pkgs, err := aptflex.ReadPackagesFile(fromFile) + if err != nil { + return fmt.Errorf("--from-file %s: %w", fromFile, err) + } + args = injectPackagesAfterInstall(args, pkgs) + } + // Extract build flags (--build-name, --build-number, --module, --project). + filteredArgs, buildConfiguration, err := build.ExtractBuildDetailsFromArgs(args) if err != nil { return err } @@ -2388,7 +2400,8 @@ func AptCmd(c *cli.Context) error { SetTrusted(trusted). SetRepoName(repoName). SetDist(dist). - SetComponent(component) + SetComponent(component). + SetBuildConfiguration(buildConfiguration) if serverDetails != nil { cmd.SetServerDetails(serverDetails) } @@ -2396,6 +2409,21 @@ func AptCmd(c *cli.Context) error { return commands.ExecWithPackageManager(cmd, "apt") } +// injectPackagesAfterInstall inserts pkgs into args immediately after the +// "install" subcommand token. If "install" is not present, pkgs are appended. +func injectPackagesAfterInstall(args, pkgs []string) []string { + for i, a := range args { + if a == "install" { + result := make([]string, 0, len(args)+len(pkgs)) + result = append(result, args[:i+1]...) + result = append(result, pkgs...) + result = append(result, args[i+1:]...) + return result + } + } + return append(args, pkgs...) +} + // aptSetupCmd handles 'jf setup apt' — writes a persistent sources.list entry. func aptSetupCmd(c *cli.Context) error { // --remove only needs root (enforced in Run); skip server/repo validation. diff --git a/go.mod b/go.mod index c1d1fe0ae..8e311e273 100644 --- a/go.mod +++ b/go.mod @@ -246,4 +246,10 @@ require ( //replace github.com/ktrysmt/go-bitbucket => github.com/ktrysmt/go-bitbucket v0.9.80 -// replace github.com/jfrog/jfrog-cli-core/v2 => github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260604085947-7c110b77b4b4 +// replace github.com/jfrog/jfrog-cli-core/v2 => github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260729061834-1c527b8abaa6 + +//replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.54.2-0.20251007084958-5eeaa42c31a6 + +replace github.com/jfrog/jfrog-cli-artifactory => github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260910055841-3cfc8c3712e2 + +replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go v1.13.1-0.20260901184543-ec0cffa4e661 diff --git a/go.sum b/go.sum index 2bed2a995..befda567d 100644 --- a/go.sum +++ b/go.sum @@ -390,8 +390,8 @@ github.com/jellydator/ttlcache/v3 v3.4.0 h1:YS4P125qQS0tNhtL6aeYkheEaB/m8HCqdMMP github.com/jellydator/ttlcache/v3 v3.4.0/go.mod h1:Hw9EgjymziQD3yGsQdf1FqFdpp7YjFMd4Srg5EJlgD4= github.com/jfrog/archiver/v3 v3.6.4 h1:qHAWCLKwo3+ocHNNoWzGZ8ESl8QQk/lR3W09Pt+ROvE= github.com/jfrog/archiver/v3 v3.6.4/go.mod h1:5V9l+Fte30Y4qe9dUOAd3yNTf8lmtVNuhKNrvI8PMhg= -github.com/jfrog/build-info-go v1.13.1-0.20260828071122-bb92ab7ba69b h1:kQRepoHjiJWwDx14CkrfBlfRHaHWf77XXWogqoMsVzU= -github.com/jfrog/build-info-go v1.13.1-0.20260828071122-bb92ab7ba69b/go.mod h1:CYRUCvLKfyARjoJXLWAxce1qNUxTEtbRKAARkV42vpE= +github.com/jfrog/build-info-go v1.13.1-0.20260901184543-ec0cffa4e661 h1:Iy9U1t1E961l7sCTuOs3xGYP3pXFxQNxgxMxzHdJaLE= +github.com/jfrog/build-info-go v1.13.1-0.20260901184543-ec0cffa4e661/go.mod h1:CYRUCvLKfyARjoJXLWAxce1qNUxTEtbRKAARkV42vpE= github.com/jfrog/froggit-go v1.23.1 h1:4wmaHeuptxVINbovMaeITzVhi3+VQoc/FFIjF4axzu0= github.com/jfrog/froggit-go v1.23.1/go.mod h1:wRDryqyp3oe+eHgME2mpnEQmO8XBECIPagFwj0nHmdI= github.com/jfrog/go-mockhttp v0.3.1 h1:/wac8v4GMZx62viZmv4wazB5GNKs+GxawuS1u3maJH8= @@ -402,8 +402,8 @@ github.com/jfrog/jfrog-apps-config v1.0.1 h1:mtv6k7g8A8BVhlHGlSveapqf4mJfonwvXYL github.com/jfrog/jfrog-apps-config v1.0.1/go.mod h1:8AIIr1oY9JuH5dylz2S6f8Ym2MaadPLR6noCBO4C22w= github.com/jfrog/jfrog-cli-application v1.0.2-0.20260621072921-cadb78770a3e h1:jUfQzLCVbUazw7FEXf3+57vQheDSHa/Px/Gp4pf/sNI= github.com/jfrog/jfrog-cli-application v1.0.2-0.20260621072921-cadb78770a3e/go.mod h1:p8yLtbmCxxQucIbLZKnWu0F+EDtj6NLXbRQCEK/nb6o= -github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260901141441-82d1b03bc083 h1:jjHlAgpi9jQMN1mhCqMmb2RnoxACSrpBks/CHNV0CGo= -github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260901141441-82d1b03bc083/go.mod h1:g3l9tPAVq/3cYRfhNEsy9TXuvK1kvt5YUSMuWKTKyUg= +github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260910055841-3cfc8c3712e2 h1:KWXseNzikekPCN9gSd2sGB6Ox07KW0o+iGyJj1SZ4jM= +github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260910055841-3cfc8c3712e2/go.mod h1:ojLACy/rvlJ0SHWo8hZLFjG1Jwu/kYamPRmeNWCHHlQ= github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260827111619-bee4d60fbdc7 h1:4ytBkQB+iBS/KbG+a974hiZbmTith6KuWa5g0Zvw+z4= github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260827111619-bee4d60fbdc7/go.mod h1:vuARjRZopsCqVcZmWzCgw5Pr9QD1FWvwFxijV4bvJJI= github.com/jfrog/jfrog-cli-evidence v0.9.5-0.20260618135203-4d2bdd4ee35f h1:MV4BATdkEoUYJmdPDvaB9EBb8JQZg28n/K4X7dcmyAY= diff --git a/testdata/apt_debian_remote_repository_config.json b/testdata/apt_debian_remote_repository_config.json index 679ea45a7..9f7a7b482 100644 --- a/testdata/apt_debian_remote_repository_config.json +++ b/testdata/apt_debian_remote_repository_config.json @@ -3,6 +3,7 @@ "rclass": "remote", "packageType": "debian", "url": "http://deb.debian.org/debian", + "debianDefaultArchitectures": "arm64,amd64", "repoLayoutRef": "simple-default", "xrayIndex": false } diff --git a/testdata/apt_remote_repository_config.json b/testdata/apt_remote_repository_config.json index e4924ab5e..e9bb03a18 100644 --- a/testdata/apt_remote_repository_config.json +++ b/testdata/apt_remote_repository_config.json @@ -3,6 +3,7 @@ "rclass": "remote", "packageType": "debian", "url": "http://archive.ubuntu.com/ubuntu", + "debianDefaultArchitectures": "amd64", "repoLayoutRef": "simple-default", "xrayIndex": false } diff --git a/testdata/apt_virtual_repository_config.json b/testdata/apt_virtual_repository_config.json index c72cfc69a..3816b5b68 100644 --- a/testdata/apt_virtual_repository_config.json +++ b/testdata/apt_virtual_repository_config.json @@ -3,6 +3,7 @@ "rclass": "virtual", "packageType": "debian", "repositories": ["${APT_LOCAL_REPO}", "${APT_REMOTE_REPO}", "${APT_DEBIAN_REMOTE_REPO}"], + "debianDefaultArchitectures": "arm64,amd64", "repoLayoutRef": "simple-default", "defaultDeploymentRepo": "${APT_LOCAL_REPO}" } diff --git a/utils/tests/consts.go b/utils/tests/consts.go index 22f4902dd..e1c9fea5f 100644 --- a/utils/tests/consts.go +++ b/utils/tests/consts.go @@ -242,6 +242,7 @@ var ( AptRemoteRepo = "cli-apt-remote" AptDebianRemoteRepo = "cli-apt-debian-remote" AptVirtualRepo = "cli-apt-virtual" + AptBuildName = "cli-apt-build" PoetryLocalRepo = "cli-poetry-local" PoetryRemoteRepo = "cli-poetry-remote" PoetryVirtualRepo = "cli-poetry-virtual" diff --git a/utils/tests/utils.go b/utils/tests/utils.go index a1f42c443..1c4413dc4 100644 --- a/utils/tests/utils.go +++ b/utils/tests/utils.go @@ -534,6 +534,7 @@ func GetBuildNames() []string { TestPipenv: {&PipenvBuildName}, TestPoetry: {&PoetryBuildName}, TestUv: {&UvBuildName}, + TestApt: {&AptBuildName}, TestNix: {&NixBuildName}, TestCargo: {&CargoBuildName}, TestAlpine: {&AlpineBuildName}, @@ -707,6 +708,7 @@ func AddTimestampToGlobalVars() { AptRemoteRepo += uniqueSuffix AptDebianRemoteRepo += uniqueSuffix AptVirtualRepo += uniqueSuffix + AptBuildName += uniqueSuffix ConanLocalRepo += uniqueSuffix ConanRemoteRepo += uniqueSuffix ConanVirtualRepo += uniqueSuffix