Skip to content

RTECO-2003: register jf choco and add the Chocolatey test suite - #3708

Open
bhanurp wants to merge 6 commits into
masterfrom
RTECO-2003-choco-flexpack
Open

RTECO-2003: register jf choco and add the Chocolatey test suite#3708
bhanurp wants to merge 6 commits into
masterfrom
RTECO-2003-choco-flexpack

Conversation

@bhanurp

@bhanurp bhanurp commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Registers the choco build tool, wires jf setup choco through the existing setup family, and adds the Chocolatey integration suite. Final PR of RTECO-2003.

jf setup choco needs no registration of its own — the setup family is driven off GetSupportedPackageManagersList(). The build tool is registered with SkipFlagParsing so Chocolatey's own flags reach the native client untouched, and wrapped in WrapCmdWithCurationPostFailureRun passing techutils.Nuget: Chocolatey packages are .nupkg files served from NuGet repos, so a separate technology would duplicate NuGet's configuration for no behavioural gain.

There is no legacy jf rt choco-* path, so the command is FlexPack-only by construction and needs no JFROG_RUN_NATIVE gate.

Tests

21 integration tests behind -test.choco, reusing the existing NuGet repositories since Artifactory documents Chocolatey under NuGet and has no distinct package type.

Beyond pack/push/install coverage, three tests pin native behaviours that are easy to assume away — each fails silently rather than loudly:

  • choco pack --output-directory still records its artifact
  • a bare choco push (no positional path) still records the package Chocolatey found in the folder
  • an installed package's version is resolved from its .nuspec, since lib/<id>/<id>.nupkg carries no version in the file name

The suite also asserts the statelessness contract — no .jfrog/projects, and no change to Chocolatey's machine-wide source list — and that pass-through subcommands neither collect build-info nor require a configured JFrog server.

CI

Runs on windows-2022, which ships Chocolatey 2.7.4. The job fails early if a runner ever ships older than 2.0, since choco apikey add is the 2.x verb (on 1.x a bare choco apikey only lists keys).

A second, cheap Linux job covers the one behaviour observable only where Chocolatey cannot run: the OS gate, and that --help still works anyway.

One gap worth stating: GitHub-hosted Windows runners run as administrator with UAC disabled, so the non-elevated failure path for jf setup choco is unreachable in CI. It is covered by a unit test in jfrog-cli-artifactory instead.

Dependencies

Pins jfrog/build-info-go#425, jfrog/jfrog-cli-core#1616 and jfrog/jfrog-cli-artifactory#556. All three must merge first; the go.mod pins are then re-pointed at their merged commits.

Test plan

  • go build ./..., go vet .
  • All 21 choco tests discovered and gated behind -test.choco
  • Windows CI run green (requires build-gate approval)

🤖 Generated with Claude Code

Registers the choco build tool and wires `jf setup choco` through the existing
setup family, which is driven off GetSupportedPackageManagersList() and so needs
no registration of its own. The command is registered with SkipFlagParsing so
Chocolatey's own flags reach the native client untouched, and is wrapped in
WrapCmdWithCurationPostFailureRun passing techutils.Nuget -- Chocolatey packages
are .nupkg files served from NuGet repos, so a separate technology would
duplicate NuGet's configuration for no behavioural gain.

There is no legacy `jf rt choco-*` path, so the command is FlexPack-only by
construction and needs no JFROG_RUN_NATIVE gate.

Adds choco_test.go (21 integration tests) behind -test.choco, reusing the
existing NuGet repositories since Artifactory documents Chocolatey under NuGet
and has no distinct package type. Beyond pack/push/install coverage, the suite
pins three native behaviours that are easy to assume away, each of which fails
silently rather than loudly:

- `choco pack --output-directory` still records its artifact.
- A bare `choco push`, with no positional path, still records the package
  Chocolatey found in the folder.
- An installed package's version is resolved from its .nuspec, since
  lib/<id>/<id>.nupkg carries no version in the file name.

It also asserts the statelessness contract -- no .jfrog/projects and no change to
Chocolatey's machine-wide source list -- and that pass-through subcommands
neither collect build-info nor require a configured JFrog server.

The workflow runs on windows-2022, which ships Chocolatey 2.7.4, and fails early
if the runner ever ships older than 2.0, since `choco apikey add` is the 2.x verb.
A second, cheap Linux job covers the one behaviour only observable where
Chocolatey cannot run: the OS gate, and that --help still works anyway.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@bhanurp bhanurp added new feature Automatically generated release notes safe to test Approve running integration tests on a pull request labels Sep 10, 2026
Picks up the lint fixes in both, so this branch builds against the same commits
CI runs there.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Build the pass-through arg list as a fresh slice. Appending onto testCase.args
  is free to reuse that slice backing array, which would leak the build flags
  into the next case.
- Drop a dead const left over from an earlier draft of the redaction test, which
  asserts against the real credential rather than a placeholder.
- Assert the published artifact in the installed-version test. That confirms the
  fixture really is at 3.4.5 before the recorded version is checked, so a wrong
  version cannot be blamed on a bad fixture -- and it gives chocoArtifactPath a
  caller whose version is not 1.0.0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Same three high CVEs Frogbot flagged on the artifactory PR, cleared the same way
by moving to x/crypto v0.56.0 before this branch inherits them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Same two high CVEs Frogbot flagged on the artifactory PR after the x/crypto
bump, cleared the same way before this branch inherits them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

🚨 Frogbot scanned this pull request and found the below:

View full scan results in JFrog Platform

📗 Scan Summary

  • Frogbot scanned for vulnerabilities and found 3 issues
Scan Category Status Security Issues
Software Composition Analysis ✅ Done Not Found
Contextual Analysis ✅ Done -
Static Application Security Testing (SAST) ✅ Done
3 Issues Found 3 Low
Secrets ✅ Done Not Found
Services ✅ Done Not Found
Infrastructure as Code (IaC) ✅ Done Not Found

@github-actions

Copy link
Copy Markdown
Contributor
NpmLocalRepositoryConfig

at utils/tests/consts.go (line 96)

🎯 Static Application Security Testing (SAST) Vulnerability

Severity Finding
low
Low
Credentials for restricted resources included directly in source code
Full description

Vulnerability Details

Rule ID: go-hardcoded-credentials

Overview

Hardcoded credentials are usernames, passwords, API keys, or other secrets
embedded directly in source code. This practice, identified by CWE-798, is
highly insecure because it makes it easy for anyone with access to the code to
discover and misuse the credentials. If the code is publicly released, shared,
or leaked, the credentials will be exposed to unauthorized parties.

Vulnerable example

In this example, the database username and password for the frog pond are
hardcoded directly in the source code as string literals. This is a major
security risk, as anyone who can read this file can steal the credentials and
gain unauthorized access to the database.

package main

import (
	"database/sql"
	"fmt"
	"log"

	_ "[github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)"
)

func main() {
	// VULNERABLE: Hardcoded database credentials for the frog pond.
	frogUser := "pond_admin"
	frogPassword := "LeapFlog123!"
	pondName := "lilypad_db"

	connStr := fmt.Sprintf("%s:%s@tcp(127.0.0.1:3306)/%s",
		frogUser, frogPassword, pondName)

	lilypadDB, err := sql.Open("mysql", connStr)
	if err != nil {
		log.Fatalf("Error opening database: %v", err)
	}
	defer lilypadDB.Close()

	err = lilypadDB.Ping()
	if err != nil {
		log.Fatalf("Error pinging database: %v", err)
	}
	fmt.Println("Successfully connected to the frog pond.")
}

Remediation

The remediated code retrieves the database credentials from environment
variables instead of hardcoding them. This is a much more secure approach, as
it separates the secrets from the source code. This allows credentials to be
managed securely by deployment systems and rotated without changing the code.

package main

import (
	"database/sql"
	"fmt"
	"log"
	"os"

	_ "[github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)"
)

func main() {
	// SECURE: Retrieve credentials from environment variables.
	frogUser := os.Getenv("FROG_DB_USER")
	frogPassword := os.Getenv("FROG_DB_PASS")
	pondName := os.Getenv("FROG_DB_NAME")

	if frogUser == "" || frogPassword == "" || pondName == "" {
		log.Fatal("DB credentials are not set in environment variables.")
	}

	connStr := fmt.Sprintf("%s:%s@tcp(127.0.0.1:3306)/%s",
		frogUser, frogPassword, pondName)

	lilypadDB, err := sql.Open("mysql", connStr)
	if err != nil {
		log.Fatalf("Error opening database: %v", err)
	}
	defer lilypadDB.Close()

	err = lilypadDB.Ping()
	if err != nil {
		log.Fatalf("Error pinging database: %v", err)
	}
	fmt.Println("Successfully connected to the frog pond.")
}



@github-actions

Copy link
Copy Markdown
Contributor
NpmLocalScopedRespositoryConfig

at utils/tests/consts.go (line 97)

🎯 Static Application Security Testing (SAST) Vulnerability

Severity Finding
low
Low
Credentials for restricted resources included directly in source code
Full description

Vulnerability Details

Rule ID: go-hardcoded-credentials

Overview

Hardcoded credentials are usernames, passwords, API keys, or other secrets
embedded directly in source code. This practice, identified by CWE-798, is
highly insecure because it makes it easy for anyone with access to the code to
discover and misuse the credentials. If the code is publicly released, shared,
or leaked, the credentials will be exposed to unauthorized parties.

Vulnerable example

In this example, the database username and password for the frog pond are
hardcoded directly in the source code as string literals. This is a major
security risk, as anyone who can read this file can steal the credentials and
gain unauthorized access to the database.

package main

import (
	"database/sql"
	"fmt"
	"log"

	_ "[github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)"
)

func main() {
	// VULNERABLE: Hardcoded database credentials for the frog pond.
	frogUser := "pond_admin"
	frogPassword := "LeapFlog123!"
	pondName := "lilypad_db"

	connStr := fmt.Sprintf("%s:%s@tcp(127.0.0.1:3306)/%s",
		frogUser, frogPassword, pondName)

	lilypadDB, err := sql.Open("mysql", connStr)
	if err != nil {
		log.Fatalf("Error opening database: %v", err)
	}
	defer lilypadDB.Close()

	err = lilypadDB.Ping()
	if err != nil {
		log.Fatalf("Error pinging database: %v", err)
	}
	fmt.Println("Successfully connected to the frog pond.")
}

Remediation

The remediated code retrieves the database credentials from environment
variables instead of hardcoding them. This is a much more secure approach, as
it separates the secrets from the source code. This allows credentials to be
managed securely by deployment systems and rotated without changing the code.

package main

import (
	"database/sql"
	"fmt"
	"log"
	"os"

	_ "[github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)"
)

func main() {
	// SECURE: Retrieve credentials from environment variables.
	frogUser := os.Getenv("FROG_DB_USER")
	frogPassword := os.Getenv("FROG_DB_PASS")
	pondName := os.Getenv("FROG_DB_NAME")

	if frogUser == "" || frogPassword == "" || pondName == "" {
		log.Fatal("DB credentials are not set in environment variables.")
	}

	connStr := fmt.Sprintf("%s:%s@tcp(127.0.0.1:3306)/%s",
		frogUser, frogPassword, pondName)

	lilypadDB, err := sql.Open("mysql", connStr)
	if err != nil {
		log.Fatalf("Error opening database: %v", err)
	}
	defer lilypadDB.Close()

	err = lilypadDB.Ping()
	if err != nil {
		log.Fatalf("Error pinging database: %v", err)
	}
	fmt.Println("Successfully connected to the frog pond.")
}



@github-actions

Copy link
Copy Markdown
Contributor
NpmRemoteRepositoryConfig

at utils/tests/consts.go (line 98)

🎯 Static Application Security Testing (SAST) Vulnerability

Severity Finding
low
Low
Credentials for restricted resources included directly in source code
Full description

Vulnerability Details

Rule ID: go-hardcoded-credentials

Overview

Hardcoded credentials are usernames, passwords, API keys, or other secrets
embedded directly in source code. This practice, identified by CWE-798, is
highly insecure because it makes it easy for anyone with access to the code to
discover and misuse the credentials. If the code is publicly released, shared,
or leaked, the credentials will be exposed to unauthorized parties.

Vulnerable example

In this example, the database username and password for the frog pond are
hardcoded directly in the source code as string literals. This is a major
security risk, as anyone who can read this file can steal the credentials and
gain unauthorized access to the database.

package main

import (
	"database/sql"
	"fmt"
	"log"

	_ "[github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)"
)

func main() {
	// VULNERABLE: Hardcoded database credentials for the frog pond.
	frogUser := "pond_admin"
	frogPassword := "LeapFlog123!"
	pondName := "lilypad_db"

	connStr := fmt.Sprintf("%s:%s@tcp(127.0.0.1:3306)/%s",
		frogUser, frogPassword, pondName)

	lilypadDB, err := sql.Open("mysql", connStr)
	if err != nil {
		log.Fatalf("Error opening database: %v", err)
	}
	defer lilypadDB.Close()

	err = lilypadDB.Ping()
	if err != nil {
		log.Fatalf("Error pinging database: %v", err)
	}
	fmt.Println("Successfully connected to the frog pond.")
}

Remediation

The remediated code retrieves the database credentials from environment
variables instead of hardcoding them. This is a much more secure approach, as
it separates the secrets from the source code. This allows credentials to be
managed securely by deployment systems and rotated without changing the code.

package main

import (
	"database/sql"
	"fmt"
	"log"
	"os"

	_ "[github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)"
)

func main() {
	// SECURE: Retrieve credentials from environment variables.
	frogUser := os.Getenv("FROG_DB_USER")
	frogPassword := os.Getenv("FROG_DB_PASS")
	pondName := os.Getenv("FROG_DB_NAME")

	if frogUser == "" || frogPassword == "" || pondName == "" {
		log.Fatal("DB credentials are not set in environment variables.")
	}

	connStr := fmt.Sprintf("%s:%s@tcp(127.0.0.1:3306)/%s",
		frogUser, frogPassword, pondName)

	lilypadDB, err := sql.Open("mysql", connStr)
	if err != nil {
		log.Fatalf("Error opening database: %v", err)
	}
	defer lilypadDB.Close()

	err = lilypadDB.Ping()
	if err != nil {
		log.Fatalf("Error pinging database: %v", err)
	}
	fmt.Println("Successfully connected to the frog pond.")
}



@bhanurp
bhanurp requested review from a team, agrasth, fluxxBot, itsmeleela, naveenku-jfrog and reshmifrog and removed request for a team September 10, 2026 04:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new feature Automatically generated release notes safe to test Approve running integration tests on a pull request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant