Skip to content

Commit 723250b

Browse files
authored
Add support for packages on OpenBSD (#6607)
It's similar to other BSD systems but of course it's different. Signed-off-by: Tim Smith <tsmith84@gmail.com>
1 parent 4f3ad4b commit 723250b

File tree

4 files changed

+160
-0
lines changed

4 files changed

+160
-0
lines changed
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// Copyright (c) Mondoo, Inc.
2+
// SPDX-License-Identifier: BUSL-1.1
3+
4+
package packages
5+
6+
import (
7+
"bufio"
8+
"fmt"
9+
"io"
10+
"strings"
11+
12+
"github.com/rs/zerolog/log"
13+
14+
"go.mondoo.com/cnquery/v12/providers/os/connection/shared"
15+
)
16+
17+
const (
18+
OpenbsdPkgFormat = "openbsd"
19+
)
20+
21+
// ParseOpenbsdPackages parses the output of 'pkg_info -a' on OpenBSD.
22+
// Each line has the format: name-version description
23+
func ParseOpenbsdPackages(r io.Reader) ([]Package, error) {
24+
pkgs := []Package{}
25+
26+
scanner := bufio.NewScanner(r)
27+
for scanner.Scan() {
28+
line := scanner.Text()
29+
if strings.TrimSpace(line) == "" {
30+
continue
31+
}
32+
33+
pkg, err := parseOpenbsdPackageLine(line)
34+
if err != nil {
35+
log.Debug().Err(err).Msg("skipping invalid openbsd package line")
36+
continue
37+
}
38+
pkgs = append(pkgs, pkg)
39+
}
40+
41+
if err := scanner.Err(); err != nil {
42+
return nil, err
43+
}
44+
45+
return pkgs, nil
46+
}
47+
48+
// parseOpenbsdPackageLine parses a single line from pkg_info output.
49+
// Format: "name-version description text"
50+
// The name-version field never contains spaces, so we split on the first space.
51+
func parseOpenbsdPackageLine(line string) (Package, error) {
52+
idx := strings.IndexByte(line, ' ')
53+
if idx == -1 {
54+
return Package{}, fmt.Errorf("could not parse package line: %s", line)
55+
}
56+
57+
nameVersion := line[:idx]
58+
description := strings.TrimSpace(line[idx:])
59+
60+
// Split name and version using the same regex as NetBSD.
61+
// Package names can contain hyphens; the version starts with a digit.
62+
matches := netbsdPkgNameRegex.FindStringSubmatch(nameVersion)
63+
if len(matches) != 3 {
64+
return Package{}, fmt.Errorf("could not parse package name and version from: %s", nameVersion)
65+
}
66+
67+
return Package{
68+
Name: matches[1],
69+
Version: matches[2],
70+
Description: description,
71+
Format: OpenbsdPkgFormat,
72+
}, nil
73+
}
74+
75+
type OpenBSDPkgManager struct {
76+
conn shared.Connection
77+
}
78+
79+
func (o *OpenBSDPkgManager) Name() string {
80+
return "OpenBSD Package Manager"
81+
}
82+
83+
func (o *OpenBSDPkgManager) List() ([]Package, error) {
84+
cmd, err := o.conn.RunCommand("pkg_info -a")
85+
if err != nil {
86+
return nil, fmt.Errorf("could not read openbsd package list")
87+
}
88+
89+
return ParseOpenbsdPackages(cmd.Stdout)
90+
}
91+
92+
func (o *OpenBSDPkgManager) Available() (map[string]PackageUpdate, error) {
93+
return map[string]PackageUpdate{}, nil
94+
}
95+
96+
func (o *OpenBSDPkgManager) Files(name string, version string, arch string) ([]FileRecord, error) {
97+
return nil, nil
98+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright (c) Mondoo, Inc.
2+
// SPDX-License-Identifier: BUSL-1.1
3+
4+
package packages
5+
6+
import (
7+
"os"
8+
"testing"
9+
10+
"github.com/stretchr/testify/assert"
11+
"github.com/stretchr/testify/require"
12+
)
13+
14+
func TestParseOpenbsdPackages(t *testing.T) {
15+
f, err := os.Open("testdata/openbsd-pkg-info.txt")
16+
require.NoError(t, err)
17+
defer f.Close()
18+
19+
pkgs, err := ParseOpenbsdPackages(f)
20+
require.NoError(t, err)
21+
assert.Equal(t, 11, len(pkgs))
22+
23+
// Test simple package
24+
assert.Equal(t, "bash", pkgs[1].Name)
25+
assert.Equal(t, "5.2.26", pkgs[1].Version)
26+
assert.Equal(t, "GNU Bourne Again Shell", pkgs[1].Description)
27+
assert.Equal(t, OpenbsdPkgFormat, pkgs[1].Format)
28+
29+
// Test package with pN revision suffix
30+
assert.Equal(t, "bzip2", pkgs[2].Name)
31+
assert.Equal(t, "1.0.8p0", pkgs[2].Version)
32+
33+
// Test package with pN revision suffix in version
34+
assert.Equal(t, "python", pkgs[6].Name)
35+
assert.Equal(t, "3.11.8p0", pkgs[6].Version)
36+
37+
// Test package with flavor suffix (vim-9.1.100-no_x11)
38+
assert.Equal(t, "vim", pkgs[8].Name)
39+
assert.Equal(t, "9.1.100-no_x11", pkgs[8].Version)
40+
41+
// Test package with hyphen in name (git-lfs)
42+
assert.Equal(t, "git-lfs", pkgs[10].Name)
43+
assert.Equal(t, "3.4.1", pkgs[10].Version)
44+
45+
// Verify all packages have the openbsd format
46+
for _, pkg := range pkgs {
47+
assert.Equal(t, OpenbsdPkgFormat, pkg.Format)
48+
}
49+
}

providers/os/resources/packages/packages.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ func ResolveSystemPkgManagers(conn shared.Connection) ([]OperatingSystemPkgManag
135135
pms = append(pms, &FreeBSDPkgManager{conn: conn})
136136
case asset.Platform.Name == "netbsd":
137137
pms = append(pms, &NetBSDPkgManager{conn: conn})
138+
case asset.Platform.Name == "openbsd":
139+
pms = append(pms, &OpenBSDPkgManager{conn: conn})
138140
case asset.Platform.Name == "aix":
139141
pms = append(pms, &AixPkgManager{conn: conn, platform: asset.Platform})
140142
case asset.Platform.Name == "gentoo":
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
aom-3.7.0 AV1 codec library
2+
bash-5.2.26 GNU Bourne Again Shell
3+
bzip2-1.0.8p0 block-sorting file compressor, unencumbered
4+
curl-8.6.0 command line tool for transferring data with URL syntax
5+
git-2.44.0 distributed version control system
6+
nano-7.2 small and friendly text editor, strstrippeddown Pico clone
7+
python-3.11.8p0 interpreted object-oriented programming language
8+
quirks-7.14 exceptions to the ports tree
9+
vim-9.1.100-no_x11 vi clone, many additional features
10+
xz-5.4.5 LZMA compression and decompression tools
11+
git-lfs-3.4.1 Git extension for versioning large files

0 commit comments

Comments
 (0)