Skip to content

Commit

Permalink
Add GPG key verification for RPM packages
Browse files Browse the repository at this point in the history
Signed-off-by: Igor Shishkin <me@teran.dev>
  • Loading branch information
teran committed Aug 18, 2024
1 parent 8ecc25c commit 83ef2ab
Show file tree
Hide file tree
Showing 9 changed files with 394 additions and 89 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ on:
tags:
- 'v*'

env:
CGO_ENABLED: 0

jobs:
buf:
runs-on: ubuntu-latest
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ on:
- edited
- synchronize

env:
CGO_ENABLED: 0

jobs:
buf:
runs-on: ubuntu-latest
Expand Down
136 changes: 136 additions & 0 deletions cli/lazyblob/lazyblob.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package lazyblob

import (
"context"
"io"
"net/http"
"os"
"sync"

"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
)

const userAgent = "Mozilla/5.0 (compatible; archived-cli/lazyblob; +https://github.com/teran/archived)"

type LazyBLOB interface {
URL() string
File(ctx context.Context) (*os.File, error)
Filename(ctx context.Context) (string, error)
Close() error
}

type lazyblob struct {
url string
tempDir string
length int64
mutex *sync.RWMutex
tempFilename string
}

func New(url, tempDir string, length int64) LazyBLOB {
log.WithFields(log.Fields{
"url": url,
"length": length,
"tempdir": tempDir,
}).Debug("lazyblob initialized")

return &lazyblob{
url: url,
tempDir: tempDir,
length: length,
mutex: &sync.RWMutex{},
}
}

func (l *lazyblob) download(ctx context.Context) error {
l.mutex.Lock()
defer l.mutex.Unlock()

if l.tempFilename != "" {
return nil
}

req, err := http.NewRequestWithContext(ctx, http.MethodGet, l.url, nil)
if err != nil {
return err
}

req.Header.Set("User-Agent", userAgent)

resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()

if err := os.MkdirAll(l.tempDir, 0o700); err != nil {
return err
}

tempFile, err := os.CreateTemp(l.tempDir, "package_*.rpm.tmp")
if err != nil {
return err
}
defer tempFile.Close()

n, err := io.Copy(tempFile, resp.Body)
if err != nil {
return err
}

if n != l.length {
return io.ErrShortWrite
}

l.tempFilename = tempFile.Name()

return nil
}

func (l *lazyblob) newReadCloser() (*os.File, error) {
l.mutex.RLock()
defer l.mutex.RUnlock()

if l.tempFilename == "" {
return nil, errors.New("file is not downloaded yet")
}

return os.Open(l.tempFilename)
}

func (l *lazyblob) File(ctx context.Context) (*os.File, error) {
if l.tempFilename == "" {
if err := l.download(ctx); err != nil {
return nil, err
}
}

return l.newReadCloser()
}

func (l *lazyblob) Filename(ctx context.Context) (string, error) {
if l.tempFilename == "" {
if err := l.download(ctx); err != nil {
return "", err
}
}

return l.tempFilename, nil
}

func (l *lazyblob) URL() string {
return l.url
}

func (l *lazyblob) Close() error {
l.mutex.Lock()
defer l.mutex.Unlock()

if err := os.RemoveAll(l.tempDir); err != nil {
return err
}

l.tempFilename = ""
return nil
}
60 changes: 60 additions & 0 deletions cli/lazyblob/lazyblob_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package lazyblob

import (
"context"
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"

echo "github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)

func TestLazyblob(t *testing.T) {
ctx := context.TODO()
r := require.New(t)

m := &testHandlerMock{}
defer m.AssertExpectations(t)

m.On("StaticFile", "/").Return(http.StatusOK, "text/plain", []byte("test data")).Once()

e := echo.New()
e.Use(middleware.Logger())
e.Use(middleware.Recover())
e.GET("/*", m.StaticFile)

srv := httptest.NewServer(e)
defer srv.Close()

lb := New(srv.URL, t.TempDir(), 9)
defer lb.Close()

fn, err := lb.Filename(ctx)
r.NoError(err)
r.True(strings.HasSuffix(fn, ".rpm.tmp"))

fp, err := lb.File(ctx)
r.NoError(err)
defer fp.Close()

data, err := io.ReadAll(fp)
r.NoError(err)
r.Equal("test data", string(data))

url := lb.URL()
r.Equal(srv.URL, url)
}

type testHandlerMock struct {
mock.Mock
}

func (m *testHandlerMock) StaticFile(c echo.Context) error {
args := m.Called(c.Request().RequestURI)
return c.Blob(args.Int(0), args.String(1), args.Get(2).([]byte))
}
Loading

0 comments on commit 83ef2ab

Please # to comment.