RTECO-2003: register jf choco and add the Chocolatey test suite - #3708
RTECO-2003: register jf choco and add the Chocolatey test suite#3708bhanurp wants to merge 6 commits into
Conversation
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>
# Conflicts: # go.mod # go.sum
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>
View full scan results in JFrog Platform📗 Scan Summary
|
at 🎯 Static Application Security Testing (SAST) VulnerabilityFull descriptionVulnerability Details
OverviewHardcoded credentials are usernames, passwords, API keys, or other secrets Vulnerable exampleIn this example, the database username and password for the frog pond are 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.")
}RemediationThe remediated code retrieves the database credentials from environment 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.")
} |
at 🎯 Static Application Security Testing (SAST) VulnerabilityFull descriptionVulnerability Details
OverviewHardcoded credentials are usernames, passwords, API keys, or other secrets Vulnerable exampleIn this example, the database username and password for the frog pond are 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.")
}RemediationThe remediated code retrieves the database credentials from environment 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.")
} |
at 🎯 Static Application Security Testing (SAST) VulnerabilityFull descriptionVulnerability Details
OverviewHardcoded credentials are usernames, passwords, API keys, or other secrets Vulnerable exampleIn this example, the database username and password for the frog pond are 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.")
}RemediationThe remediated code retrieves the database credentials from environment 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.")
} |


Summary
Registers the
chocobuild tool, wiresjf setup chocothrough the existing setup family, and adds the Chocolatey integration suite. Final PR of RTECO-2003.jf setup choconeeds no registration of its own — the setup family is driven offGetSupportedPackageManagersList(). The build tool is registered withSkipFlagParsingso Chocolatey's own flags reach the native client untouched, and wrapped inWrapCmdWithCurationPostFailureRunpassingtechutils.Nuget: Chocolatey packages are.nupkgfiles 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 noJFROG_RUN_NATIVEgate.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-directorystill records its artifactchoco push(no positional path) still records the package Chocolatey found in the folder.nuspec, sincelib/<id>/<id>.nupkgcarries no version in the file nameThe 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, sincechoco apikey addis the 2.x verb (on 1.x a barechoco apikeyonly lists keys).A second, cheap Linux job covers the one behaviour observable only where Chocolatey cannot run: the OS gate, and that
--helpstill 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 chocois 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.modpins are then re-pointed at their merged commits.Test plan
go build ./...,go vet .-test.choco🤖 Generated with Claude Code