Skip to content

Commit

Permalink
refactor(turborepo): Signature Authentication (2nd try) (#4980)
Browse files Browse the repository at this point in the history
### Description

Refactors the signature authentication to use a language-independent
algorithm, as the previous implementation depended on Go's JSON
serialization.

NOTE: This is a global hash bump.

### Testing Instructions

Testing is using fuzzing across the Go-Rust boundary to check that
signatures are correctly generated on both sides.

---------

Co-authored-by: --global <Nicholas Yang>
  • Loading branch information
NicholasLYang committed May 18, 2023
1 parent 4b91af9 commit 0ee7128
Show file tree
Hide file tree
Showing 59 changed files with 1,547 additions and 260 deletions.
4 changes: 2 additions & 2 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ linker = "rust-lld"
xtask = "run --package xtask --"
tr-build = "build -p turbo"
tr-run = "run -p turbo"
tr-test = "test -p turborepo-* -p turbopath -p vercel-api-mock --features rustls-tls"
tr-check = "check -p turbo -p vercel-api-mock"
tr-test = "test -p turborepo-* -p turbopath -p vercel-api-mock -p turborepo-cache --features rustls-tls"
tr-check = "check -p turbo -p vercel-api-mock -p turborepo-ffi"
# Builds all test code to check for compiler errors before running
tp-pre-test = "nextest run --no-run --workspace --release --exclude turbo --exclude turborepo-* --exclude turbopath --exclude vercel-api-mock"
tp-test = "nextest run --workspace --release --no-fail-fast --exclude turbo --exclude turborepo-* --exclude turbopath --exclude vercel-api-mock"
Expand Down
76 changes: 76 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ turbopack-tests = { path = "crates/turbopack-tests" }
turbopath = { path = "crates/turborepo-paths" }
turborepo = { path = "crates/turborepo" }
turborepo-api-client = { path = "crates/turborepo-api-client" }
turborepo-cache = { path = "crates/turborepo-cache" }
turborepo-ffi = { path = "crates/turborepo-ffi" }
turborepo-fs = { path = "crates/turborepo-fs" }
turborepo-lib = { path = "crates/turborepo-lib" }
Expand Down
2 changes: 1 addition & 1 deletion cli/internal/cache/cache_http.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ func newHTTPCache(opts Opts, client client, recorder analytics.Recorder, repoRoo
signerVerifier: &ArtifactSignatureAuthentication{
// TODO(Gaspar): this should use RemoteCacheOptions.TeamId once we start
// enforcing team restrictions for repositories.
teamId: client.GetTeamID(),
teamID: client.GetTeamID(),
enabled: opts.RemoteCacheOpts.Signature,
},
}
Expand Down
36 changes: 17 additions & 19 deletions cli/internal/cache/cache_signature_authentication.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,17 @@ import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"hash"
"os"
)

type ArtifactSignatureAuthentication struct {
teamId string
enabled bool
teamID string
// Used for testing purposes
secretKeyOverride []byte
enabled bool
}

func (asa *ArtifactSignatureAuthentication) isEnabled() bool {
Expand All @@ -25,12 +26,18 @@ func (asa *ArtifactSignatureAuthentication) isEnabled() bool {

// If the secret key is not found or the secret key length is 0, an error is returned
// Preference is given to the environment specified secret key.
func (asa *ArtifactSignatureAuthentication) secretKey() ([]byte, error) {
secret := os.Getenv("TURBO_REMOTE_CACHE_SIGNATURE_KEY")
func (asa *ArtifactSignatureAuthentication) getSecretKey() ([]byte, error) {
var secret []byte
if asa.secretKeyOverride != nil {
secret = asa.secretKeyOverride
} else {
secret = []byte(os.Getenv("TURBO_REMOTE_CACHE_SIGNATURE_KEY"))
}

if len(secret) == 0 {
return nil, errors.New("signature secret key not found. You must specify a secret key in the TURBO_REMOTE_CACHE_SIGNATURE_KEY environment variable")
}
return []byte(secret), nil
return secret, nil
}

func (asa *ArtifactSignatureAuthentication) generateTag(hash string, artifactBody []byte) (string, error) {
Expand All @@ -43,22 +50,13 @@ func (asa *ArtifactSignatureAuthentication) generateTag(hash string, artifactBod
}

func (asa *ArtifactSignatureAuthentication) getTagGenerator(hash string) (hash.Hash, error) {
teamId := asa.teamId
secret, err := asa.secretKey()
if err != nil {
return nil, err
}
artifactMetadata := &struct {
Hash string `json:"hash"`
TeamId string `json:"teamId"`
}{
Hash: hash,
TeamId: teamId,
}
metadata, err := json.Marshal(artifactMetadata)
teamID := asa.teamID
secret, err := asa.getSecretKey()
if err != nil {
return nil, err
}
metadata := []byte(hash)
metadata = append(metadata, []byte(teamID)...)

// TODO(Gaspar) Support additional signing algorithms here
h := hmac.New(sha256.New, secret)
Expand Down
Loading

0 comments on commit 0ee7128

Please sign in to comment.