fix: address PR #32 review findings
- Add --batch --no-tty to all GPG invocations (fixes TestManifestTamperedSignatureFails hang)
- Add 'reserved 304' to mf.proto for removed atime field
- Restore IncludeDotfiles alias on include-dotfiles flag
- Replace http.Get with http.Client{Timeout: 30s} in manifest_loader.go
This commit is contained in:
parent
e27f8a6c3b
commit
ca93d80f1e
@ -5,6 +5,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
@ -18,7 +19,8 @@ func isHTTPURL(s string) bool {
|
|||||||
// The caller must close the returned reader.
|
// The caller must close the returned reader.
|
||||||
func (mfa *CLIApp) openManifestReader(pathOrURL string) (io.ReadCloser, error) {
|
func (mfa *CLIApp) openManifestReader(pathOrURL string) (io.ReadCloser, error) {
|
||||||
if isHTTPURL(pathOrURL) {
|
if isHTTPURL(pathOrURL) {
|
||||||
resp, err := http.Get(pathOrURL) //nolint:gosec // user-provided URL is intentional
|
client := &http.Client{Timeout: 30 * time.Second}
|
||||||
|
resp, err := client.Get(pathOrURL) //nolint:gosec // user-provided URL is intentional
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to fetch %s: %w", pathOrURL, err)
|
return nil, fmt.Errorf("failed to fetch %s: %w", pathOrURL, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -128,7 +128,8 @@ func (mfa *CLIApp) run(args []string) {
|
|||||||
Usage: "Resolve encountered symlinks",
|
Usage: "Resolve encountered symlinks",
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "include-dotfiles",
|
Name: "include-dotfiles",
|
||||||
|
Aliases: []string{"IncludeDotfiles"},
|
||||||
|
|
||||||
Usage: "Include dot (hidden) files (excluded by default)",
|
Usage: "Include dot (hidden) files (excluded by default)",
|
||||||
},
|
},
|
||||||
@ -220,7 +221,8 @@ func (mfa *CLIApp) run(args []string) {
|
|||||||
Usage: "Resolve encountered symlinks",
|
Usage: "Resolve encountered symlinks",
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "include-dotfiles",
|
Name: "include-dotfiles",
|
||||||
|
Aliases: []string{"IncludeDotfiles"},
|
||||||
|
|
||||||
Usage: "Include dot (hidden) files (excluded by default)",
|
Usage: "Include dot (hidden) files (excluded by default)",
|
||||||
},
|
},
|
||||||
|
|||||||
14
mfer/gpg.go
14
mfer/gpg.go
@ -20,7 +20,7 @@ type SigningOptions struct {
|
|||||||
// gpgSign creates a detached signature of the data using the specified key.
|
// gpgSign creates a detached signature of the data using the specified key.
|
||||||
// Returns the armored detached signature.
|
// Returns the armored detached signature.
|
||||||
func gpgSign(data []byte, keyID GPGKeyID) ([]byte, error) {
|
func gpgSign(data []byte, keyID GPGKeyID) ([]byte, error) {
|
||||||
cmd := exec.Command("gpg",
|
cmd := exec.Command("gpg", "--batch", "--no-tty",
|
||||||
"--detach-sign",
|
"--detach-sign",
|
||||||
"--armor",
|
"--armor",
|
||||||
"--local-user", string(keyID),
|
"--local-user", string(keyID),
|
||||||
@ -42,7 +42,7 @@ func gpgSign(data []byte, keyID GPGKeyID) ([]byte, error) {
|
|||||||
// gpgExportPublicKey exports the public key for the specified key ID.
|
// gpgExportPublicKey exports the public key for the specified key ID.
|
||||||
// Returns the armored public key.
|
// Returns the armored public key.
|
||||||
func gpgExportPublicKey(keyID GPGKeyID) ([]byte, error) {
|
func gpgExportPublicKey(keyID GPGKeyID) ([]byte, error) {
|
||||||
cmd := exec.Command("gpg",
|
cmd := exec.Command("gpg", "--batch", "--no-tty",
|
||||||
"--export",
|
"--export",
|
||||||
"--armor",
|
"--armor",
|
||||||
string(keyID),
|
string(keyID),
|
||||||
@ -65,7 +65,7 @@ func gpgExportPublicKey(keyID GPGKeyID) ([]byte, error) {
|
|||||||
|
|
||||||
// gpgGetKeyFingerprint gets the full fingerprint for a key ID.
|
// gpgGetKeyFingerprint gets the full fingerprint for a key ID.
|
||||||
func gpgGetKeyFingerprint(keyID GPGKeyID) ([]byte, error) {
|
func gpgGetKeyFingerprint(keyID GPGKeyID) ([]byte, error) {
|
||||||
cmd := exec.Command("gpg",
|
cmd := exec.Command("gpg", "--batch", "--no-tty",
|
||||||
"--with-colons",
|
"--with-colons",
|
||||||
"--fingerprint",
|
"--fingerprint",
|
||||||
string(keyID),
|
string(keyID),
|
||||||
@ -114,7 +114,7 @@ func gpgExtractPubKeyFingerprint(pubKey []byte) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Import the public key into the temporary keyring
|
// Import the public key into the temporary keyring
|
||||||
importCmd := exec.Command("gpg",
|
importCmd := exec.Command("gpg", "--batch", "--no-tty",
|
||||||
"--homedir", tmpDir,
|
"--homedir", tmpDir,
|
||||||
"--import",
|
"--import",
|
||||||
pubKeyFile,
|
pubKeyFile,
|
||||||
@ -126,7 +126,7 @@ func gpgExtractPubKeyFingerprint(pubKey []byte) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// List keys to get fingerprint
|
// List keys to get fingerprint
|
||||||
listCmd := exec.Command("gpg",
|
listCmd := exec.Command("gpg", "--batch", "--no-tty",
|
||||||
"--homedir", tmpDir,
|
"--homedir", tmpDir,
|
||||||
"--with-colons",
|
"--with-colons",
|
||||||
"--fingerprint",
|
"--fingerprint",
|
||||||
@ -184,7 +184,7 @@ func gpgVerify(data, signature, pubKey []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Import the public key into the temporary keyring
|
// Import the public key into the temporary keyring
|
||||||
importCmd := exec.Command("gpg",
|
importCmd := exec.Command("gpg", "--batch", "--no-tty",
|
||||||
"--homedir", tmpDir,
|
"--homedir", tmpDir,
|
||||||
"--import",
|
"--import",
|
||||||
pubKeyFile,
|
pubKeyFile,
|
||||||
@ -196,7 +196,7 @@ func gpgVerify(data, signature, pubKey []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Verify the signature
|
// Verify the signature
|
||||||
verifyCmd := exec.Command("gpg",
|
verifyCmd := exec.Command("gpg", "--batch", "--no-tty",
|
||||||
"--homedir", tmpDir,
|
"--homedir", tmpDir,
|
||||||
"--verify",
|
"--verify",
|
||||||
sigFile,
|
sigFile,
|
||||||
|
|||||||
@ -339,7 +339,7 @@ type MFFilePath struct {
|
|||||||
// optional per-file metadata
|
// optional per-file metadata
|
||||||
MimeType *string `protobuf:"bytes,301,opt,name=mimeType,proto3,oneof" json:"mimeType,omitempty"`
|
MimeType *string `protobuf:"bytes,301,opt,name=mimeType,proto3,oneof" json:"mimeType,omitempty"`
|
||||||
Mtime *Timestamp `protobuf:"bytes,302,opt,name=mtime,proto3,oneof" json:"mtime,omitempty"`
|
Mtime *Timestamp `protobuf:"bytes,302,opt,name=mtime,proto3,oneof" json:"mtime,omitempty"`
|
||||||
Ctime *Timestamp `protobuf:"bytes,303,opt,name=ctime,proto3,oneof" json:"ctime,omitempty"` // Field 304 (atime) removed — not useful for integrity verification.
|
Ctime *Timestamp `protobuf:"bytes,303,opt,name=ctime,proto3,oneof" json:"ctime,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
@ -561,7 +561,7 @@ const file_mf_proto_rawDesc = "" +
|
|||||||
"\n" +
|
"\n" +
|
||||||
"_signatureB\t\n" +
|
"_signatureB\t\n" +
|
||||||
"\a_signerB\x10\n" +
|
"\a_signerB\x10\n" +
|
||||||
"\x0e_signingPubKey\"\xf0\x01\n" +
|
"\x0e_signingPubKey\"\xf8\x01\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"MFFilePath\x12\x12\n" +
|
"MFFilePath\x12\x12\n" +
|
||||||
"\x04path\x18\x01 \x01(\tR\x04path\x12\x12\n" +
|
"\x04path\x18\x01 \x01(\tR\x04path\x12\x12\n" +
|
||||||
@ -574,7 +574,7 @@ const file_mf_proto_rawDesc = "" +
|
|||||||
".TimestampH\x02R\x05ctime\x88\x01\x01B\v\n" +
|
".TimestampH\x02R\x05ctime\x88\x01\x01B\v\n" +
|
||||||
"\t_mimeTypeB\b\n" +
|
"\t_mimeTypeB\b\n" +
|
||||||
"\x06_mtimeB\b\n" +
|
"\x06_mtimeB\b\n" +
|
||||||
"\x06_ctime\".\n" +
|
"\x06_ctimeJ\x06\b\xb0\x02\x10\xb1\x02\".\n" +
|
||||||
"\x0eMFFileChecksum\x12\x1c\n" +
|
"\x0eMFFileChecksum\x12\x1c\n" +
|
||||||
"\tmultiHash\x18\x01 \x01(\fR\tmultiHash\"\xd6\x01\n" +
|
"\tmultiHash\x18\x01 \x01(\fR\tmultiHash\"\xd6\x01\n" +
|
||||||
"\x06MFFile\x12)\n" +
|
"\x06MFFile\x12)\n" +
|
||||||
|
|||||||
@ -60,6 +60,7 @@ message MFFilePath {
|
|||||||
optional Timestamp mtime = 302;
|
optional Timestamp mtime = 302;
|
||||||
optional Timestamp ctime = 303;
|
optional Timestamp ctime = 303;
|
||||||
// Field 304 (atime) removed — not useful for integrity verification.
|
// Field 304 (atime) removed — not useful for integrity verification.
|
||||||
|
reserved 304;
|
||||||
}
|
}
|
||||||
|
|
||||||
message MFFileChecksum {
|
message MFFileChecksum {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user