Skip to content

Commit

Permalink
Merge pull request #5878 from thaJeztah/trust_cleans
Browse files Browse the repository at this point in the history
Assorted cleanups to reduce trust / notary imports
  • Loading branch information
thaJeztah authored Mar 3, 2025
2 parents 124716b + c7072a8 commit 076ec3b
Show file tree
Hide file tree
Showing 12 changed files with 87 additions and 137 deletions.
29 changes: 8 additions & 21 deletions cli/command/image/trust.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func TrustedPush(ctx context.Context, cli command.Cli, repoInfo *registry.Reposi
func PushTrustedReference(ctx context.Context, ioStreams command.Streams, repoInfo *registry.RepositoryInfo, ref reference.Named, authConfig registrytypes.AuthConfig, in io.Reader) error {
// If it is a trusted push we would like to find the target entry which match the
// tag provided in the function and then do an AddTarget later.
target := &client.Target{}
notaryTarget := &client.Target{}
// Count the times of calling for handleTarget,
// if it is called more that once, that should be considered an error in a trusted push.
cnt := 0
Expand All @@ -65,12 +65,12 @@ func PushTrustedReference(ctx context.Context, ioStreams command.Streams, repoIn
if dgst, err := digest.Parse(pushResult.Digest); err == nil {
h, err := hex.DecodeString(dgst.Hex())
if err != nil {
target = nil
notaryTarget = nil
return
}
target.Name = pushResult.Tag
target.Hashes = data.Hashes{string(dgst.Algorithm()): h}
target.Length = int64(pushResult.Size)
notaryTarget.Name = pushResult.Tag
notaryTarget.Hashes = data.Hashes{string(dgst.Algorithm()): h}
notaryTarget.Length = int64(pushResult.Size)
}
}
}
Expand Down Expand Up @@ -99,7 +99,7 @@ func PushTrustedReference(ctx context.Context, ioStreams command.Streams, repoIn
return errors.Errorf("internal error: only one call to handleTarget expected")
}

if target == nil {
if notaryTarget == nil {
return errors.Errorf("no targets found, provide a specific tag in order to sign it")
}

Expand Down Expand Up @@ -134,10 +134,10 @@ func PushTrustedReference(ctx context.Context, ioStreams command.Streams, repoIn
return trust.NotaryError(repoInfo.Name.Name(), err)
}
_, _ = fmt.Fprintf(ioStreams.Out(), "Finished initializing %q\n", repoInfo.Name.Name())
err = repo.AddTarget(target, data.CanonicalTargetsRole)
err = repo.AddTarget(notaryTarget, data.CanonicalTargetsRole)
case nil:
// already initialized and we have successfully downloaded the latest metadata
err = AddTargetToAllSignableRoles(repo, target)
err = trust.AddToAllSignableRoles(repo, notaryTarget)
default:
return trust.NotaryError(repoInfo.Name.Name(), err)
}
Expand All @@ -155,19 +155,6 @@ func PushTrustedReference(ctx context.Context, ioStreams command.Streams, repoIn
return nil
}

// AddTargetToAllSignableRoles attempts to add the image target to all the top level delegation roles we can
// (based on whether we have the signing key and whether the role's path allows
// us to).
// If there are no delegation roles, we add to the targets role.
func AddTargetToAllSignableRoles(repo client.Repository, target *client.Target) error {
signableRoles, err := trust.GetSignableRoles(repo, target)
if err != nil {
return err
}

return repo.AddTarget(target, signableRoles...)
}

// trustedPull handles content trust pulling of an image
func trustedPull(ctx context.Context, cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth, opts PullOptions) error {
refs, err := getTrustedPullTargets(cli, imgRefAndAuth)
Expand Down
57 changes: 0 additions & 57 deletions cli/command/image/trust_test.go

This file was deleted.

6 changes: 6 additions & 0 deletions cli/command/trust/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,9 @@ func getOrGenerateRootKeyAndInitRepo(notaryRepo client.Repository) error {
}
return notaryRepo.Initialize([]string{rootKey.ID()}, data.CanonicalSnapshotRole)
}

const testPass = "password"

func testPassRetriever(string, string, bool, int) (string, bool, error) {
return testPass, false, nil
}
18 changes: 0 additions & 18 deletions cli/command/trust/helpers_test.go

This file was deleted.

5 changes: 1 addition & 4 deletions cli/command/trust/key_generate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"github.com/docker/cli/cli/config"
"github.com/docker/cli/internal/test"
"github.com/theupdateframework/notary"
"github.com/theupdateframework/notary/passphrase"
"github.com/theupdateframework/notary/trustmanager"
tufutils "github.com/theupdateframework/notary/tuf/utils"
"gotest.tools/v3/assert"
Expand Down Expand Up @@ -51,11 +50,9 @@ func TestGenerateKeySuccess(t *testing.T) {
pubKeyCWD := t.TempDir()
privKeyStorageDir := t.TempDir()

const testPass = "password"
cannedPasswordRetriever := passphrase.ConstantRetriever(testPass)
// generate a single key
keyName := "alice"
privKeyFileStore, err := trustmanager.NewKeyFileStore(privKeyStorageDir, cannedPasswordRetriever)
privKeyFileStore, err := trustmanager.NewKeyFileStore(privKeyStorageDir, testPassRetriever)
assert.NilError(t, err)

pubKeyPEM, err := generateKeyAndOutputPubPEM(keyName, privKeyFileStore)
Expand Down
11 changes: 3 additions & 8 deletions cli/command/trust/key_load_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"github.com/docker/cli/cli/config"
"github.com/docker/cli/internal/test"
"github.com/theupdateframework/notary"
"github.com/theupdateframework/notary/passphrase"
"github.com/theupdateframework/notary/storage"
"github.com/theupdateframework/notary/trustmanager"
tufutils "github.com/theupdateframework/notary/tuf/utils"
Expand Down Expand Up @@ -122,8 +121,6 @@ func TestLoadKeyFromPath(t *testing.T) {

keyStorageDir := t.TempDir()

const passwd = "password"
cannedPasswordRetriever := passphrase.ConstantRetriever(passwd)
keyFileStore, err := storage.NewPrivateKeyFileStorage(keyStorageDir, notary.KeyExtension)
assert.NilError(t, err)
privKeyImporters := []trustmanager.Importer{keyFileStore}
Expand All @@ -133,7 +130,7 @@ func TestLoadKeyFromPath(t *testing.T) {
assert.NilError(t, err)

// import the key to our keyStorageDir
assert.Check(t, loadPrivKeyBytesToStore(privKeyBytes, privKeyImporters, privKeyFilepath, "signer-name", cannedPasswordRetriever))
assert.Check(t, loadPrivKeyBytesToStore(privKeyBytes, privKeyImporters, privKeyFilepath, "signer-name", testPassRetriever))

// check that the appropriate ~/<trust_dir>/private/<key_id>.key file exists
expectedImportKeyPath := filepath.Join(keyStorageDir, notary.PrivDir, keyID+"."+notary.KeyExtension)
Expand All @@ -151,7 +148,7 @@ func TestLoadKeyFromPath(t *testing.T) {
// assert encrypted header
assert.Check(t, is.Equal("ENCRYPTED PRIVATE KEY", keyPEM.Type))

decryptedKey, err := tufutils.ParsePKCS8ToTufKey(keyPEM.Bytes, []byte(passwd))
decryptedKey, err := tufutils.ParsePKCS8ToTufKey(keyPEM.Bytes, []byte(testPass))
assert.NilError(t, err)
fixturePEM, _ := pem.Decode(keyBytes)
assert.Check(t, is.DeepEqual(fixturePEM.Bytes, decryptedKey.Private()))
Expand Down Expand Up @@ -213,8 +210,6 @@ func TestLoadPubKeyFailure(t *testing.T) {
assert.NilError(t, os.WriteFile(pubKeyFilepath, pubKeyFixture, notary.PrivNoExecPerms))
keyStorageDir := t.TempDir()

const passwd = "password"
cannedPasswordRetriever := passphrase.ConstantRetriever(passwd)
keyFileStore, err := storage.NewPrivateKeyFileStorage(keyStorageDir, notary.KeyExtension)
assert.NilError(t, err)
privKeyImporters := []trustmanager.Importer{keyFileStore}
Expand All @@ -223,7 +218,7 @@ func TestLoadPubKeyFailure(t *testing.T) {
assert.NilError(t, err)

// import the key to our keyStorageDir - it should fail
err = loadPrivKeyBytesToStore(pubKeyBytes, privKeyImporters, pubKeyFilepath, "signer-name", cannedPasswordRetriever)
err = loadPrivKeyBytesToStore(pubKeyBytes, privKeyImporters, pubKeyFilepath, "signer-name", testPassRetriever)
expected := fmt.Sprintf("provided file %s is not a supported private key - to add a signer's public key use docker trust signer add", pubKeyFilepath)
assert.Error(t, err, expected)
}
10 changes: 0 additions & 10 deletions cli/command/trust/revoke_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import (
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/notary"
"github.com/theupdateframework/notary/client"
"github.com/theupdateframework/notary/passphrase"
"github.com/theupdateframework/notary/trustpinning"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
"gotest.tools/v3/golden"
Expand Down Expand Up @@ -151,14 +149,6 @@ func TestTrustRevokeCommand(t *testing.T) {
}
}

func TestGetSignableRolesForTargetAndRemoveError(t *testing.T) {
notaryRepo, err := client.NewFileCachedRepository(t.TempDir(), "gun", "https://localhost", nil, passphrase.ConstantRetriever("password"), trustpinning.TrustPinConfig{})
assert.NilError(t, err)
target := client.Target{}
err = getSignableRolesForTargetAndRemove(target, notaryRepo)
assert.Error(t, err, "client is offline")
}

func TestRevokeTrustPromptTermination(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
Expand Down
2 changes: 1 addition & 1 deletion cli/command/trust/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ func signAndPublishToTarget(out io.Writer, imgRefAndAuth trust.ImageRefAndAuth,
if err != nil {
return err
}
err = image.AddTargetToAllSignableRoles(notaryRepo, &target)
err = trust.AddToAllSignableRoles(notaryRepo, &target)
if err == nil {
prettyPrintExistingSignatureInfo(out, existingSigInfo)
err = notaryRepo.Publish()
Expand Down
15 changes: 6 additions & 9 deletions cli/command/trust/sign_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,13 @@ import (
"github.com/theupdateframework/notary"
"github.com/theupdateframework/notary/client"
"github.com/theupdateframework/notary/client/changelist"
"github.com/theupdateframework/notary/passphrase"
"github.com/theupdateframework/notary/trustpinning"
"github.com/theupdateframework/notary/tuf/data"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
"gotest.tools/v3/skip"
)

const passwd = "password"

func TestTrustSignCommandErrors(t *testing.T) {
testCases := []struct {
name string
Expand Down Expand Up @@ -83,7 +80,7 @@ func TestTrustSignCommandOfflineErrors(t *testing.T) {
}

func TestGetOrGenerateNotaryKey(t *testing.T) {
notaryRepo, err := client.NewFileCachedRepository(t.TempDir(), "gun", "https://localhost", nil, passphrase.ConstantRetriever(passwd), trustpinning.TrustPinConfig{})
notaryRepo, err := client.NewFileCachedRepository(t.TempDir(), "gun", "https://localhost", nil, testPassRetriever, trustpinning.TrustPinConfig{})
assert.NilError(t, err)

// repo is empty, try making a root key
Expand Down Expand Up @@ -126,7 +123,7 @@ func TestGetOrGenerateNotaryKey(t *testing.T) {
func TestAddStageSigners(t *testing.T) {
skip.If(t, runtime.GOOS == "windows", "FIXME: not supported currently")

notaryRepo, err := client.NewFileCachedRepository(t.TempDir(), "gun", "https://localhost", nil, passphrase.ConstantRetriever(passwd), trustpinning.TrustPinConfig{})
notaryRepo, err := client.NewFileCachedRepository(t.TempDir(), "gun", "https://localhost", nil, testPassRetriever, trustpinning.TrustPinConfig{})
assert.NilError(t, err)

// stage targets/user
Expand Down Expand Up @@ -207,7 +204,7 @@ func TestAddStageSigners(t *testing.T) {
}

func TestGetSignedManifestHashAndSize(t *testing.T) {
notaryRepo, err := client.NewFileCachedRepository(t.TempDir(), "gun", "https://localhost", nil, passphrase.ConstantRetriever(passwd), trustpinning.TrustPinConfig{})
notaryRepo, err := client.NewFileCachedRepository(t.TempDir(), "gun", "https://localhost", nil, testPassRetriever, trustpinning.TrustPinConfig{})
assert.NilError(t, err)
_, _, err = getSignedManifestHashAndSize(notaryRepo, "test")
assert.Error(t, err, "client is offline")
Expand All @@ -229,7 +226,7 @@ func TestGetReleasedTargetHashAndSize(t *testing.T) {
}

func TestCreateTarget(t *testing.T) {
notaryRepo, err := client.NewFileCachedRepository(t.TempDir(), "gun", "https://localhost", nil, passphrase.ConstantRetriever(passwd), trustpinning.TrustPinConfig{})
notaryRepo, err := client.NewFileCachedRepository(t.TempDir(), "gun", "https://localhost", nil, testPassRetriever, trustpinning.TrustPinConfig{})
assert.NilError(t, err)
_, err = createTarget(notaryRepo, "")
assert.Error(t, err, "no tag specified")
Expand All @@ -238,7 +235,7 @@ func TestCreateTarget(t *testing.T) {
}

func TestGetExistingSignatureInfoForReleasedTag(t *testing.T) {
notaryRepo, err := client.NewFileCachedRepository(t.TempDir(), "gun", "https://localhost", nil, passphrase.ConstantRetriever(passwd), trustpinning.TrustPinConfig{})
notaryRepo, err := client.NewFileCachedRepository(t.TempDir(), "gun", "https://localhost", nil, testPassRetriever, trustpinning.TrustPinConfig{})
assert.NilError(t, err)
_, err = getExistingSignatureInfoForReleasedTag(notaryRepo, "test")
assert.Error(t, err, "client is offline")
Expand Down Expand Up @@ -267,7 +264,7 @@ func TestSignCommandChangeListIsCleanedOnError(t *testing.T) {
err := cmd.Execute()
assert.Assert(t, err != nil)

notaryRepo, err := client.NewFileCachedRepository(tmpDir, "docker.io/library/ubuntu", "https://localhost", nil, passphrase.ConstantRetriever(passwd), trustpinning.TrustPinConfig{})
notaryRepo, err := client.NewFileCachedRepository(tmpDir, "docker.io/library/ubuntu", "https://localhost", nil, testPassRetriever, trustpinning.TrustPinConfig{})
assert.NilError(t, err)
cl, err := notaryRepo.GetChangelist()
assert.NilError(t, err)
Expand Down
19 changes: 17 additions & 2 deletions cli/trust/trust.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,11 @@ var (
ActionsPullOnly = []string{"pull"}
// ActionsPushAndPull defines the actions for read-write interactions with a Notary Repository
ActionsPushAndPull = []string{"pull", "push"}
// NotaryServer is the endpoint serving the Notary trust server
NotaryServer = "https://notary.docker.io"
)

// NotaryServer is the endpoint serving the Notary trust server
const NotaryServer = "https://notary.docker.io"

// GetTrustDirectory returns the base trust directory name
func GetTrustDirectory() string {
return filepath.Join(config.Dir(), "trust")
Expand Down Expand Up @@ -238,6 +239,20 @@ func NotaryError(repoName string, err error) error {
return err
}

// AddToAllSignableRoles attempts to add the image target to all the top level
// delegation roles we can (based on whether we have the signing key and whether
// the role's path allows us to).
//
// If there are no delegation roles, we add to the targets role.
func AddToAllSignableRoles(repo client.Repository, target *client.Target) error {
signableRoles, err := GetSignableRoles(repo, target)
if err != nil {
return err
}

return repo.AddTarget(target, signableRoles...)
}

// GetSignableRoles returns a list of roles for which we have valid signing
// keys, given a notary repository and a target
func GetSignableRoles(repo client.Repository, target *client.Target) ([]data.RoleName, error) {
Expand Down
Loading

0 comments on commit 076ec3b

Please sign in to comment.