feat: update AMI name and enhance scanner upload process for improved efficiency

This commit is contained in:
Hari Om 2026-05-19 09:53:06 +05:30
parent 288cecaf66
commit 3ec8bb8811
2 changed files with 117 additions and 55 deletions

View file

@ -7,7 +7,7 @@ packer {
}
}
source "amazon-ebs" "ubuntu" {
ami_name = "test16"
ami_name = "test17"
instance_type = "t2.large"
region = "us-west-2"
source_ami_filter {
@ -37,11 +37,8 @@ build {
inline = ["echo 'packer works'"]
}
provisioner "hcp-sbom" {
# source = "registry.hcp.hashicorp.com/native-sbom/aws"
auto_generate = true
scan_path = "/usr/bin"
# scanner_url = "file:///Users/anurag.sharma/ptemplates/my/aws/syft/mysyft"
# scanner_checksum = "3d5e9f5c069d8054d3cb3fbe3f2521f13e2bcc7867eee177be0b1bcd7c32da99"
destination = "sbom.json"
}
# provisioner "breakpoint" {

View file

@ -640,81 +640,146 @@ func downloadPackerRelease(ctx context.Context, goos, goarch, version string) (s
return zipPath, nil
}
// uploadScanner uploads the Packer release zip to the remote host and extracts
// the packer binary there.
// For Unix: uploads /tmp/packer-sbom-runner.zip, extracts packer, and makes
// /tmp/packer-sbom-runner executable.
// For Windows: uploads C:\Windows\Temp\packer-sbom-runner.zip and extracts
// C:\Windows\Temp\packer-sbom-runner.exe.
// uploadScanner uploads the scanner binary to the remote host.
// For Windows: uploads zip file and extracts remotely (optimization for slow WinRM uploads).
// For Unix: uploads binary directly.
//
// Unix path:
// 1. Extract local zip entry `packer`
// 2. Upload binary → /tmp/packer-sbom-runner
// 3. chmod +x → /tmp/packer-sbom-runner
//
// Windows path:
// 1. Upload zip → C:\Windows\Temp\packer-sbom-runner.zip
// 2-5. Single PowerShell command (Expand-Archive + Move-Item + Remove-Item)
func (p *Provisioner) uploadScanner(ctx context.Context, ui packersdk.Ui,
comm packersdk.Communicator, localZipPath, osType string) (string, error) {
_ = ui
isWindows := strings.Contains(strings.ToLower(osType), "windows")
var remotePath, remoteZipPath, remoteDir, binaryName string
var remotePath, binaryName string
if isWindows {
remoteDir = "C:\\Windows\\Temp"
binaryName = "packer.exe"
remoteZipPath = remoteDir + "\\packer-sbom-runner.zip"
remotePath = "C:\\Windows\\Temp\\packer-sbom-runner.exe"
} else {
remoteDir = "/tmp"
binaryName = "packer"
remoteZipPath = "/tmp/packer-sbom-runner.zip"
remotePath = "/tmp/packer-sbom-runner"
}
localFile, err := os.Open(localZipPath)
if err != nil {
return "", fmt.Errorf("failed to open Packer release zip: %s", err)
}
defer func() { _ = localFile.Close() }()
log.Printf("Uploading Packer release zip to %s...", remoteZipPath)
if err := comm.Upload(remoteZipPath, localFile, nil); err != nil {
return "", fmt.Errorf("failed to upload Packer release zip: %s", err)
}
var extractCmd string
if isWindows {
extractCmd = fmt.Sprintf(
`powershell -NoProfile -ExecutionPolicy Bypass -Command "$ErrorActionPreference='Stop'; Expand-Archive -Path '%s' -DestinationPath '%s' -Force; if (!(Test-Path '%s\\%s')) { throw 'packer binary not found in archive' }; Move-Item -Force '%s\\%s' '%s'; Remove-Item -Force '%s'"`,
remoteZipPath, remoteDir, remoteDir, binaryName, remoteDir, binaryName, remotePath, remoteZipPath,
remoteDir := "C:\\Windows\\Temp"
remoteZipPath := remoteDir + "\\packer-sbom-runner.zip"
// Step 1: upload zip to remote.
zipFile, err := os.Open(localZipPath)
if err != nil {
return "", fmt.Errorf("failed to open Packer release zip: %s", err)
}
defer func() { _ = zipFile.Close() }()
log.Printf("[INFO] Uploading Packer release zip to %s...", remoteZipPath)
if err := comm.Upload(remoteZipPath, zipFile, nil); err != nil {
return "", fmt.Errorf("failed to upload Packer release zip: %s", err)
}
// Single PowerShell command: extract, move binary, remove zip.
psCmd := fmt.Sprintf(
`powershell -NoProfile -ExecutionPolicy Bypass -Command `+
`"$ErrorActionPreference='Stop'; `+
`Expand-Archive -Path '%s' -DestinationPath '%s' -Force; `+
`if (!(Test-Path '%s\%s')) { throw 'packer.exe not found after extraction' }; `+
`Move-Item -Force '%s\%s' '%s'; `+
`Remove-Item -Force '%s'"`,
remoteZipPath, remoteDir,
remoteDir, binaryName,
remoteDir, binaryName, remotePath,
remoteZipPath,
)
if err := p.runRemoteCmd(ctx, comm, psCmd, "extract scanner (Windows)"); err != nil {
return "", err
}
} else {
extractCmd = fmt.Sprintf(
`(command -v unzip >/dev/null 2>&1 && unzip -o -j "%s" "%s" -d "%s") || (command -v bsdtar >/dev/null 2>&1 && bsdtar -xf "%s" -C "%s" "%s"); mv -f "%s/%s" "%s"; chmod +x "%s"; rm -f "%s"`,
remoteZipPath, binaryName, remoteDir,
remoteZipPath, remoteDir, binaryName,
remoteDir, binaryName, remotePath, remotePath, remoteZipPath,
)
}
cmd := &packersdk.RemoteCmd{Command: extractCmd}
if err := comm.Start(ctx, cmd); err != nil {
return "", fmt.Errorf("failed to extract scanner on remote host: %s", err)
}
cmd.Wait()
if cmd.ExitStatus() != 0 {
return "", fmt.Errorf("remote extraction command failed with exit status %d", cmd.ExitStatus())
}
if !isWindows {
verifyCmd := &packersdk.RemoteCmd{
Command: fmt.Sprintf("test -x %s", remotePath),
// Step 1: extract the binary locally from the release zip.
binaryData, err := extractBinaryFromZip(localZipPath, binaryName)
if err != nil {
return "", fmt.Errorf("failed to extract %s from Packer release zip: %w", binaryName, err)
}
if err := comm.Start(ctx, verifyCmd); err != nil {
return "", fmt.Errorf("failed to make Packer binary executable: %s", err)
// Step 2: upload binary directly to remote.
localFile := bytes.NewReader(binaryData)
log.Printf("[INFO] Uploading Packer binary to %s...", remotePath)
if err := comm.Upload(remotePath, localFile, nil); err != nil {
return "", fmt.Errorf("failed to upload Packer binary: %s", err)
}
verifyCmd.Wait()
if verifyCmd.ExitStatus() != 0 {
return "", fmt.Errorf("scanner is not executable after extraction")
// Step 3: make it executable.
chmodCmd := fmt.Sprintf(`chmod +x "%s"`, remotePath)
if err := p.runRemoteCmd(ctx, comm, chmodCmd, "chmod scanner binary"); err != nil {
return "", err
}
// Final verify: confirm binary is executable.
verifyCmd := fmt.Sprintf(`test -x "%s"`, remotePath)
if err := p.runRemoteCmd(ctx, comm, verifyCmd, "verify scanner is executable"); err != nil {
return "", fmt.Errorf("scanner binary is not executable at %s after chmod; "+
"check that /tmp is not mounted noexec on the remote host", remotePath)
}
}
return remotePath, nil
}
func extractBinaryFromZip(zipPath, binaryName string) ([]byte, error) {
zr, err := zip.OpenReader(zipPath)
if err != nil {
return nil, fmt.Errorf("failed to open zip: %w", err)
}
defer func() { _ = zr.Close() }()
for _, f := range zr.File {
if f.Name != binaryName {
continue
}
rc, err := f.Open()
if err != nil {
return nil, fmt.Errorf("failed to open %s from zip: %w", binaryName, err)
}
data, readErr := io.ReadAll(rc)
closeErr := rc.Close()
if readErr != nil {
return nil, fmt.Errorf("failed to read %s from zip: %w", binaryName, readErr)
}
if closeErr != nil {
return nil, fmt.Errorf("failed to close %s stream from zip: %w", binaryName, closeErr)
}
return data, nil
}
return nil, fmt.Errorf("%s not found in zip %s", binaryName, zipPath)
}
// runRemoteCmd runs a single shell command on the remote host and returns a
// descriptive error if it fails.
func (p *Provisioner) runRemoteCmd(ctx context.Context, comm packersdk.Communicator, cmdStr, step string) error {
var stderr bytes.Buffer
cmd := &packersdk.RemoteCmd{
Command: cmdStr,
Stderr: &stderr,
}
if err := comm.Start(ctx, cmd); err != nil {
return fmt.Errorf("failed to start remote step %q: %s", step, err)
}
cmd.Wait()
if cmd.ExitStatus() != 0 {
return fmt.Errorf("remote step %q failed (exit %d): %s",
step, cmd.ExitStatus(), strings.TrimSpace(stderr.String()))
}
return nil
}
// provisionWithNativeGeneration handles the native SBOM generation flow.
// The Packer release binary is downloaded on the host (works in air-gapped
// environments where the VM has no internet access), verified, then uploaded