Skip to content

Commit a034489

Browse files
authored
fix: gracefully handle install without signature (#41)
If the `MANIFEST` is missing the `Files.signature` then we first try looking for `driver + '.sig'` and then error out. Adds a new CLI argument `--allow-missing-signature` which will allow installing if the signature is missing.
1 parent 5932504 commit a034489

File tree

8 files changed

+86
-20
lines changed

8 files changed

+86
-20
lines changed

cmd/dbc/install.go

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
package main
44

55
import (
6+
"errors"
67
"fmt"
8+
"io/fs"
79
"os"
810
"path/filepath"
911
"strings"
@@ -18,15 +20,17 @@ import (
1820

1921
type InstallCmd struct {
2022
// URI url.URL `arg:"-u" placeholder:"URL" help:"Base URL for fetching drivers"`
21-
Driver string `arg:"positional,required" help:"Driver to install"`
22-
Version *semver.Version `arg:"-v" help:"Version to install"`
23-
Level config.ConfigLevel `arg:"-l" help:"Config level to install to (user, system)"`
23+
Driver string `arg:"positional,required" help:"Driver to install"`
24+
Version *semver.Version `arg:"-v" help:"Version to install"`
25+
Level config.ConfigLevel `arg:"-l" help:"Config level to install to (user, system)"`
26+
NoVerify bool `arg:"--no-verify" help:"Allow installation of drivers without a signature file"`
2427
}
2528

2629
func (c InstallCmd) GetModelCustom(baseModel baseModel) tea.Model {
2730
return progressiveInstallModel{
2831
Driver: c.Driver,
2932
VersionInput: c.Version,
33+
NoVerify: c.NoVerify,
3034
spinner: spinner.New(),
3135
cfg: getConfig(c.Level),
3236
baseModel: baseModel,
@@ -39,6 +43,7 @@ func (c InstallCmd) GetModel() tea.Model {
3943
return progressiveInstallModel{
4044
Driver: c.Driver,
4145
VersionInput: c.Version,
46+
NoVerify: c.NoVerify,
4247
spinner: s,
4348
cfg: getConfig(c.Level),
4449
baseModel: baseModel{
@@ -48,8 +53,8 @@ func (c InstallCmd) GetModel() tea.Model {
4853
}
4954
}
5055

51-
func verifySignature(m config.Manifest) error {
52-
if m.Files.Driver == "" {
56+
func verifySignature(m config.Manifest, noVerify bool) error {
57+
if m.Files.Driver == "" || (noVerify && m.Files.Signature == "") {
5358
return nil
5459
}
5560

@@ -61,9 +66,17 @@ func verifySignature(m config.Manifest) error {
6166
}
6267
defer lib.Close()
6368

64-
sig, err := os.Open(filepath.Join(path, m.Files.Signature))
69+
sigFile := m.Files.Signature
70+
if sigFile == "" {
71+
sigFile = m.Files.Driver + ".sig"
72+
}
73+
74+
sig, err := os.Open(filepath.Join(path, sigFile))
6575
if err != nil {
66-
return fmt.Errorf("could not open signature file: %w", err)
76+
if errors.Is(err, fs.ErrNotExist) {
77+
return fmt.Errorf("signature file '%s' for driver is missing", sigFile)
78+
}
79+
return fmt.Errorf("failed to open signature file: %w", err)
6780
}
6881
defer sig.Close()
6982

@@ -108,6 +121,7 @@ type progressiveInstallModel struct {
108121

109122
Driver string
110123
VersionInput *semver.Version
124+
NoVerify bool
111125
cfg config.Config
112126

113127
DriverPackage dbc.PkgInfo
@@ -201,7 +215,7 @@ func (m progressiveInstallModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
201215
m.state = stVerifying
202216
m.postInstallMessage = strings.Join(msg.PostInstall.Messages, "\n")
203217
return m, func() tea.Msg {
204-
if err := verifySignature(msg); err != nil {
218+
if err := verifySignature(msg, m.NoVerify); err != nil {
205219
return err
206220
}
207221
return writeDriverManifestMsg{DriverInfo: msg.DriverInfo}

cmd/dbc/install_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
package main
44

55
import (
6+
"io/fs"
67
"os"
78
"path/filepath"
89
"runtime"
@@ -126,3 +127,28 @@ func (suite *SubcommandTestSuite) TestInstallManifestOnlyDriver() {
126127
suite.FileExists(filepath.Join(suite.tempdir, "test-driver-manifest-only.toml"))
127128
}
128129
}
130+
131+
func (suite *SubcommandTestSuite) TestInstallDriverNoSignature() {
132+
m := InstallCmd{Driver: "test-driver-no-sig"}.
133+
GetModelCustom(baseModel{getDriverList: getTestDriverList, downloadPkg: downloadTestPkg})
134+
out := suite.runCmdErr(m)
135+
suite.Contains(out, "signature file 'test-driver-1-not-valid.so.sig' for driver is missing")
136+
137+
filelist := []string{}
138+
suite.NoError(fs.WalkDir(os.DirFS(suite.tempdir), ".", func(path string, d fs.DirEntry, err error) error {
139+
if d.IsDir() {
140+
return nil
141+
}
142+
143+
filelist = append(filelist, path)
144+
return nil
145+
}))
146+
147+
// currently we don't clean out the downloaded file if signature verification fails
148+
suite.Equal([]string{"test-driver-no-sig/test-driver-1-not-valid.so"}, filelist)
149+
150+
m = InstallCmd{Driver: "test-driver-no-sig", NoVerify: true}.
151+
GetModelCustom(baseModel{getDriverList: getTestDriverList, downloadPkg: downloadTestPkg})
152+
suite.validateOutput("\r[✓] searching\r\n[✓] downloading\r\n[✓] installing\r\n[✓] verifying signature\r\n"+
153+
"\r\nInstalled test-driver-no-sig 1.0.0 to "+suite.tempdir+"\r\n", suite.runCmd(m))
154+
}

cmd/dbc/search.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ var (
1919
nameStyle = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("35"))
2020
descStyle = lipgloss.NewStyle().Italic(true)
2121
bold = lipgloss.NewStyle().Bold(true)
22-
23-
archStyle = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("5"))
2422
)
2523

2624
type SearchCmd struct {

cmd/dbc/search_test.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ func (suite *SubcommandTestSuite) TestSearchCmd() {
1414
downloadPkg: downloadTestPkg})
1515
suite.validateOutput("• test-driver-1 - This is a test driver\r\n"+
1616
"• test-driver-2 - This is another test driver\r\n"+
17-
"• test-driver-manifest-only - This is manifest-only driver\r\n\r ", suite.runCmd(m))
17+
"• test-driver-manifest-only - This is manifest-only driver\r\n"+
18+
"• test-driver-no-sig - Driver manifest missing Files.signature entry\r\n\r ", suite.runCmd(m))
1819
}
1920

2021
func (suite *SubcommandTestSuite) TestSearchCmdWithInstalled() {
@@ -26,7 +27,8 @@ func (suite *SubcommandTestSuite) TestSearchCmdWithInstalled() {
2627
baseModel{getDriverList: getTestDriverList,
2728
downloadPkg: downloadTestPkg})
2829
suite.validateOutput("• test-driver-1 - This is a test driver [installed: env=>1.1.0]\r\n"+
29-
"• test-driver-2 - This is another test driver\r\n• test-driver-manifest-only - This is manifest-only driver\r\n\r ", suite.runCmd(m))
30+
"• test-driver-2 - This is another test driver\r\n• test-driver-manifest-only - This is manifest-only driver\r\n"+
31+
"• test-driver-no-sig - Driver manifest missing Files.signature entry\r\n\r ", suite.runCmd(m))
3032
}
3133

3234
func (suite *SubcommandTestSuite) TestSearchCmdVerbose() {
@@ -41,6 +43,9 @@ func (suite *SubcommandTestSuite) TestSearchCmdVerbose() {
4143
"Available Versions:\r\n ├── 2.0.0\r\n ╰── 2.1.0\r\n"+
4244
"• test-driver-manifest-only\r\n Title: Test Driver Manifest Only\r\n "+
4345
"Description: This is manifest-only driver\r\n License: Apache-2.0\r\n "+
46+
"Available Versions:\r\n ╰── 1.0.0\r\n"+
47+
"• test-driver-no-sig\r\n Title: Test Driver No Signature\r\n "+
48+
"Description: Driver manifest missing Files.signature entry\r\n License: Apache-2.0\r\n "+
4449
"Available Versions:\r\n ╰── 1.0.0\r\n\r ", suite.runCmd(m))
4550
}
4651

@@ -64,5 +69,11 @@ func (suite *SubcommandTestSuite) TestSearchCmdVerboseWithInstalled() {
6469
" Description: This is manifest-only driver\r\n"+
6570
" License: Apache-2.0\r\n"+
6671
" Available Versions:\r\n"+
72+
" ╰── 1.0.0\r\n"+
73+
"• test-driver-no-sig\r\n"+
74+
" Title: Test Driver No Signature\r\n"+
75+
" Description: Driver manifest missing Files.signature entry\r\n"+
76+
" License: Apache-2.0\r\n"+
77+
" Available Versions:\r\n"+
6778
" ╰── 1.0.0\r\n\r ", suite.runCmd(m))
6879
}

cmd/dbc/sync.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,22 +26,25 @@ var (
2626
)
2727

2828
type SyncCmd struct {
29-
Path string `arg:"-p" placeholder:"FILE" default:"./dbc.toml" help:"Drivers list to sync from"`
30-
Level config.ConfigLevel `arg:"-l" help:"Config level to install to (user, system)"`
29+
Path string `arg:"-p" placeholder:"FILE" default:"./dbc.toml" help:"Drivers list to sync from"`
30+
Level config.ConfigLevel `arg:"-l" help:"Config level to install to (user, system)"`
31+
AllowMissing bool `arg:"--allow-missing-signature" help:"Allow installation of drivers without a signature file"`
3132
}
3233

3334
func (c SyncCmd) GetModelCustom(baseModel baseModel) tea.Model {
3435
return syncModel{
35-
baseModel: baseModel,
36-
Path: c.Path,
37-
cfg: getConfig(c.Level),
36+
baseModel: baseModel,
37+
Path: c.Path,
38+
cfg: getConfig(c.Level),
39+
AllowMissing: c.AllowMissing,
3840
}
3941
}
4042

4143
func (c SyncCmd) GetModel() tea.Model {
4244
return syncModel{
43-
Path: c.Path,
44-
cfg: getConfig(c.Level),
45+
Path: c.Path,
46+
cfg: getConfig(c.Level),
47+
AllowMissing: c.AllowMissing,
4548
baseModel: baseModel{
4649
getDriverList: getDriverList,
4750
downloadPkg: downloadPkg,
@@ -54,6 +57,7 @@ type syncModel struct {
5457

5558
// path to drivers list
5659
Path string
60+
AllowMissing bool
5761
LockFilePath string
5862
// information to write the new lockfile
5963
locked LockFile
@@ -254,7 +258,7 @@ func (s syncModel) installDriver(cfg config.Config, item installItem) tea.Cmd {
254258
manifest.DriverInfo.Source = "dbc"
255259
manifest.DriverInfo.Driver.Shared.Set(config.PlatformTuple(), driverPath)
256260

257-
if err := verifySignature(manifest); err != nil {
261+
if err := verifySignature(manifest, s.AllowMissing); err != nil {
258262
return fmt.Errorf("failed to verify signature: %w", err)
259263
}
260264

cmd/dbc/sync_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ func downloadTestPkg(pkg dbc.PkgInfo) (*os.File, error) {
4242
return os.Open(filepath.Join("testdata", "test-driver-2.tar.gz"))
4343
case "test-driver-manifest-only":
4444
return os.Open(filepath.Join("testdata", "test-driver-manifest-only.tar.gz"))
45+
case "test-driver-no-sig":
46+
return os.Open(filepath.Join("testdata", "test-driver-no-sig.tar.gz"))
4547
default:
4648
return nil, fmt.Errorf("unknown driver: %s", pkg.Driver.Path)
4749
}
305 Bytes
Binary file not shown.

cmd/dbc/testdata/test_index.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,14 @@ drivers:
6060
- platform: macos_amd64
6161
- platform: macos_arm64
6262
- platform: windows_amd64
63+
- name: Test Driver No Signature
64+
description: Driver manifest missing Files.signature entry
65+
license: Apache-2.0
66+
path: test-driver-no-sig
67+
pkginfo:
68+
- version: v1.0.0
69+
packages:
70+
- platform: linux_amd64
71+
- platform: macos_amd64
72+
- platform: macos_arm64
73+
- platform: windows_amd64

0 commit comments

Comments
 (0)