mirror of
https://github.com/vee1e/gittuf.git
synced 2026-09-01 18:27:06 +00:00
Restructure storage so gittuf verification can run over backends other
than the git binary (e.g. go-git):
- pkg/githash: concrete Git object hash, stdlib-only.
gitinterface.Hash aliases it.
- pkg/gitstore: the single Storer interface (24 methods) that all
storage consumers program against, plus the shared
ErrReferenceNotFound sentinel. *gitinterface.Repository satisfies it
structurally (compile-time asserted). Also defines ConfigKey, the
canonical type for the Git config settings gittuf reads.
- pkg/rsl (from internal/rsl): entry model, codec, and readers over
gitstore.Storer; zero gitinterface/sigstore dependencies. rsl.Hash
aliases githash.Hash; nil is the unset-Hash sentinel and IsZero
matches nil and empty as well as both format zeros (no
object-format-unaware ZeroHash). Entry commits (empty tree on the
RSL ref) are owned by the package; no storer adapter.
- internal/signerverifier/gitobject: verifies commit/tag signatures
over (payload, signature) bytes, Rekor URL as an option. The storage
half is Repository.GetObjectSignature. Removes sigstore, cosign, and
gitsign from gitinterface's dependency tree.
- internal/propagation: propagation workflow, moved off pkg/rsl's
public API (its tuf directive types are internal).
- internal/{attestations,cache,policy}: storage via gitstore.Storer;
tree writing via WriteTree(blobs, subtrees).
Breaking changes to pkg/gitinterface: Repository.VerifySignature and
the verification sentinels are removed (use gitobject.Verify);
ErrReferenceNotFound now aliases gitstore's. Repository.GetGitConfig
(which returned the whole config map) is replaced by
LookupConfig(gitstore.ConfigKey), returning a single setting's value.
Policy resolves the Rekor override from git config once per
verification and extracts signed payloads once per object instead of
per key attempt.
Assisted-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Paulo Gomes <paulo@entire.io>
96 lines
3 KiB
Go
96 lines
3 KiB
Go
// Copyright The gittuf Authors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package gitinterface
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/gittuf/gittuf/internal/signerverifier/gitobject"
|
|
artifacts "github.com/gittuf/gittuf/internal/testartifacts"
|
|
"github.com/gittuf/gittuf/pkg/gitstore"
|
|
"github.com/secure-systems-lab/go-securesystemslib/signerverifier"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestCreateTestGitRepository(t *testing.T) {
|
|
t.Run("configures test identity and signing key", func(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
signingKeysDir := t.TempDir()
|
|
|
|
repo, err := createTestGitRepository(tmpDir, signingKeysDir, false)
|
|
require.Nil(t, err)
|
|
|
|
name, _, err := repo.LookupConfig(gitstore.ConfigUserName)
|
|
require.Nil(t, err)
|
|
assert.Equal(t, testName, name)
|
|
email, _, err := repo.LookupConfig(gitstore.ConfigUserEmail)
|
|
require.Nil(t, err)
|
|
assert.Equal(t, testEmail, email)
|
|
signingKey, _, err := repo.LookupConfig(gitstore.ConfigUserSigningKey)
|
|
require.Nil(t, err)
|
|
assert.Equal(t, filepath.Join(signingKeysDir, "key.pub"), signingKey)
|
|
format, _, err := repo.LookupConfig(gitstore.ConfigGPGFormat)
|
|
require.Nil(t, err)
|
|
assert.Equal(t, "ssh", format)
|
|
})
|
|
|
|
t.Run("invalid object format", func(t *testing.T) {
|
|
_, err := createTestGitRepository(t.TempDir(), t.TempDir(), false, WithObjectFormat("bogus"))
|
|
assert.Error(t, err)
|
|
})
|
|
|
|
t.Run("invalid signing keys directory", func(t *testing.T) {
|
|
signingKeysDir := filepath.Join(t.TempDir(), "keys")
|
|
require.Nil(t, os.WriteFile(signingKeysDir, nil, 0o600))
|
|
|
|
_, err := createTestGitRepository(t.TempDir(), signingKeysDir, false)
|
|
assert.Error(t, err)
|
|
})
|
|
}
|
|
|
|
func TestWriteSigningKeys(t *testing.T) {
|
|
t.Run("writes rsa key pair", func(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
|
|
require.Nil(t, writeSigningKeys(tmpDir))
|
|
|
|
privateKey, err := os.ReadFile(filepath.Join(tmpDir, "key"))
|
|
require.Nil(t, err)
|
|
assert.Equal(t, artifacts.SSHRSAPrivate, privateKey)
|
|
|
|
publicKey, err := os.ReadFile(filepath.Join(tmpDir, "key.pub"))
|
|
require.Nil(t, err)
|
|
assert.Equal(t, artifacts.SSHRSAPublicSSH, publicKey)
|
|
})
|
|
|
|
t.Run("private key write error", func(t *testing.T) {
|
|
keysDir := filepath.Join(t.TempDir(), "keys")
|
|
require.Nil(t, os.WriteFile(keysDir, nil, 0o600))
|
|
|
|
assert.Error(t, writeSigningKeys(keysDir))
|
|
})
|
|
|
|
t.Run("public key write error", func(t *testing.T) {
|
|
keysDir := t.TempDir()
|
|
require.Nil(t, os.Mkdir(filepath.Join(keysDir, "key.pub"), 0o700))
|
|
|
|
assert.Error(t, writeSigningKeys(keysDir))
|
|
})
|
|
}
|
|
|
|
// verifyObjectSignature verifies an object's signature the way callers now
|
|
// compose it: extract payload and signature from the repository, verify the
|
|
// bytes with gitobject.
|
|
func verifyObjectSignature(t *testing.T, repo *Repository, objectID Hash, key *signerverifier.SSLibKey) error {
|
|
t.Helper()
|
|
|
|
payload, signature, err := repo.GetObjectSignature(objectID)
|
|
require.Nil(t, err)
|
|
|
|
return gitobject.Verify(context.Background(), key, payload, signature)
|
|
}
|