Skip to content

Commit

Permalink
Merge branch 'main' into testing-kms
Browse files Browse the repository at this point in the history
Signed-off-by: Tom Meadows <[email protected]>
  • Loading branch information
ChaosInTheCRD authored Feb 13, 2024
2 parents 13095f1 + be37eee commit 8962cd8
Show file tree
Hide file tree
Showing 30 changed files with 1,208 additions and 752 deletions.
1 change: 0 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ taking the time to contribute!

Before starting, please take some time to familiarize yourself with the [Code of Conduct](CODE_OF_CONDUCT.md).


## Getting Started

We welcome many different types of contributions and not all of them need a
Expand Down
78 changes: 0 additions & 78 deletions CONTRIBUTORS.md

This file was deleted.

378 changes: 52 additions & 326 deletions README.md

Large diffs are not rendered by default.

27 changes: 20 additions & 7 deletions cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ package cmd

import (
"context"
"crypto"
"encoding/json"
"fmt"

Expand Down Expand Up @@ -85,12 +84,26 @@ func runRun(ctx context.Context, ro options.RunOptions, args []string, signers .
attestors = append(attestors, commandrun.New(commandrun.WithCommand(args), commandrun.WithTracing(ro.Tracing)))
}

addtlAttestors, err := attestation.Attestors(ro.Attestations)
if err != nil {
return fmt.Errorf("failed to create attestors := %w", err)
for _, a := range ro.Attestations {
duplicate := false
for _, att := range attestors {
if a != att.Name() {
} else {
log.Warnf("Attestator %s already declared, skipping", a)
duplicate = true
break
}
}

if !duplicate {
attestor, err := attestation.GetAttestor(a)
if err != nil {
return fmt.Errorf("failed to create attestor: %w", err)
}
attestors = append(attestors, attestor)
}
}

attestors = append(attestors, addtlAttestors...)
for _, attestor := range attestors {
setters, ok := ro.AttestorOptSetters[attestor.Name()]
if !ok {
Expand All @@ -103,13 +116,13 @@ func runRun(ctx context.Context, ro options.RunOptions, args []string, signers .
}
}

var roHashes []crypto.Hash
var roHashes []cryptoutil.DigestValue
for _, hashStr := range ro.Hashes {
hash, err := cryptoutil.HashFromString(hashStr)
if err != nil {
return fmt.Errorf("failed to parse hash: %w", err)
}
roHashes = append(roHashes, hash)
roHashes = append(roHashes, cryptoutil.DigestValue{Hash: hash, GitOID: false})
}

defer out.Close()
Expand Down
75 changes: 75 additions & 0 deletions cmd/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,20 @@ import (
"crypto/rand"
"crypto/rsa"
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"
"testing"

"github.com/in-toto/go-witness/cryptoutil"
"github.com/in-toto/go-witness/dsse"
"github.com/in-toto/go-witness/log"
"github.com/in-toto/go-witness/signer"
"github.com/in-toto/go-witness/signer/file"
"github.com/in-toto/witness/options"
"github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -171,3 +176,73 @@ func TestRunHashesOptions(t *testing.T) {
})
}
}

func TestRunDuplicateAttestors(t *testing.T) {
tests := []struct {
name string
attestors []string
expectWarn int
}{
{
name: "No duplicate attestors",
attestors: []string{"environment"},
expectWarn: 0,
},
{
name: "duplicate attestors",
attestors: []string{"environment", "environment"},
expectWarn: 1,
},
{
name: "duplicate attestor due to default",
attestors: []string{"product"},
expectWarn: 1,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
fmt.Println(tt.name)
testLogger, hook := test.NewNullLogger()
log.SetLogger(testLogger)

privatekey, err := rsa.GenerateKey(rand.Reader, keybits)
require.NoError(t, err)
signer := cryptoutil.NewRSASigner(privatekey, crypto.SHA256)

workingDir := t.TempDir()
attestationPath := filepath.Join(workingDir, "outfile.txt")
runOptions := options.RunOptions{
WorkingDir: workingDir,
Attestations: tt.attestors,
OutFilePath: attestationPath,
StepName: "teststep",
Tracing: false,
}

args := []string{
"bash",
"-c",
"echo 'test' > test.txt",
}

err = runRun(context.Background(), runOptions, args, signer)
if tt.expectWarn > 0 {
c := 0
for _, entry := range hook.AllEntries() {
fmt.Println(tt.name, "log:", entry.Message)
if entry.Level == logrus.WarnLevel && strings.Contains(entry.Message, "already declared, skipping") {
c++
}
}
assert.Equal(t, tt.expectWarn, c)
} else {
require.NoError(t, err)
attestationBytes, err := os.ReadFile(attestationPath)
require.NoError(t, err)
env := dsse.Envelope{}
require.NoError(t, json.Unmarshal(attestationBytes, &env))
}
})
}
}
2 changes: 1 addition & 1 deletion cmd/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func runVerify(ctx context.Context, vo options.VerifyOptions, verifiers ...crypt

subjects := []cryptoutil.DigestSet{}
if len(vo.ArtifactFilePath) > 0 {
artifactDigestSet, err := cryptoutil.CalculateDigestSetFromFile(vo.ArtifactFilePath, []crypto.Hash{crypto.SHA256})
artifactDigestSet, err := cryptoutil.CalculateDigestSetFromFile(vo.ArtifactFilePath, []cryptoutil.DigestValue{{Hash: crypto.SHA256, GitOID: false}})
if err != nil {
return fmt.Errorf("failed to calculate artifact digest: %w", err)
}
Expand Down
10 changes: 4 additions & 6 deletions cmd/verify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func TestRunVerifyCA(t *testing.T) {
require.NoError(t, runRun(context.Background(), s1RunOptions, step1Args, signers...))

subjects := []string{}
artifactDigest, err := cryptoutil.CalculateDigestSetFromFile(artifactPath, []crypto.Hash{crypto.SHA256})
artifactDigest, err := cryptoutil.CalculateDigestSetFromFile(artifactPath, []cryptoutil.DigestValue{{Hash: crypto.SHA256}})
require.NoError(t, err)

for _, digest := range artifactDigest {
Expand Down Expand Up @@ -128,7 +128,7 @@ func TestRunVerifyCA(t *testing.T) {
require.NoError(t, runVerify(context.Background(), vo))

// test that verify works without artifactfilepath but the subject of the modified articact also provided
artifactDigest, err = cryptoutil.CalculateDigestSetFromFile(artifactPath, []crypto.Hash{crypto.SHA256})
artifactDigest, err = cryptoutil.CalculateDigestSetFromFile(artifactPath, []cryptoutil.DigestValue{{Hash: crypto.SHA256}})
require.NoError(t, err)
for _, digest := range artifactDigest {
subjects = append(subjects, digest)
Expand Down Expand Up @@ -190,7 +190,7 @@ func TestRunVerifyKeyPair(t *testing.T) {
require.NoError(t, runRun(context.Background(), s1RunOptions, step1Args, signers...))

subjects := []string{}
artifactDigest, err := cryptoutil.CalculateDigestSetFromFile(artifactPath, []crypto.Hash{crypto.SHA256})
artifactDigest, err := cryptoutil.CalculateDigestSetFromFile(artifactPath, []cryptoutil.DigestValue{{Hash: crypto.SHA256}})
require.NoError(t, err)

for _, digest := range artifactDigest {
Expand Down Expand Up @@ -226,7 +226,7 @@ func TestRunVerifyKeyPair(t *testing.T) {
require.NoError(t, runVerify(context.Background(), vo))

// test that verify works without artifactfilepath but the subject of the modified articact also provided
artifactDigest, err = cryptoutil.CalculateDigestSetFromFile(artifactPath, []crypto.Hash{crypto.SHA256})
artifactDigest, err = cryptoutil.CalculateDigestSetFromFile(artifactPath, []cryptoutil.DigestValue{{Hash: crypto.SHA256}})
require.NoError(t, err)
for _, digest := range artifactDigest {
subjects = append(subjects, digest)
Expand Down Expand Up @@ -328,9 +328,7 @@ func makepolicy(t *testing.T, functionary policy.Functionary, publicKey policy.P
p.Steps[step02.Name] = step02

if publicKey.KeyID != "" {

p.PublicKeys[publicKey.KeyID] = publicKey

}

pb, err := json.MarshalIndent(p, "", " ")
Expand Down
29 changes: 25 additions & 4 deletions docgen/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
package main

import (
"bytes"
"flag"
"log"
"fmt"
"os"

"github.com/in-toto/witness/cmd"
"github.com/spf13/cobra/doc"
Expand All @@ -30,8 +32,27 @@ func init() {
}

func main() {
// Generate CLI docs
if err := doc.GenMarkdownTree(cmd.New(), directory); err != nil {
log.Fatalf("Error generating docs: %s", err)
mdContent := "# Witness CLI Reference\n\nThis is the reference for the Witness command line tool, generated by [Cobra](https://cobra.dev/).\n\n"
// Generate markdown content for all commands
for _, command := range cmd.New().Commands() {
// We are not generating docs for the completion command right now, as it doesn't render in Markdown correctly
if command.Use == "completion [bash|zsh|fish|powershell]" {
continue
}

buf := new(bytes.Buffer)
err := doc.GenMarkdown(command, buf)
if err != nil {
fmt.Println("Error generating markdown for command:", command.Use)
continue
}
mdContent += buf.String()
}

// Write the combined markdown content to a file
err := os.WriteFile(fmt.Sprintf("%s/commands.md", directory), []byte(mdContent), 0644)
if err != nil {
fmt.Println("Error writing to file:", err)
os.Exit(1)
}
}
2 changes: 1 addition & 1 deletion docgen/verify.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ set -e
# Verify that generated Markdown docs are up-to-date.
tmpdir=$(mktemp -d)
tmpdir2=$(mktemp -d)
cp docs/witness*.md "$tmpdir2/"
cp docs/commands.md "$tmpdir2/"
go run ./docgen --dir "$tmpdir"
echo "###########################################"
echo "If diffs are found, run: make docgen"
Expand Down
11 changes: 11 additions & 0 deletions docs/about/how-witness-works.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# How Witness Works

### Signing
Witness is able to observe your software development life-cycle (SDLC) by wrapping around commands executed within them. By passing any command to Witness as an argument, the tool is able to understand what was executed but also on what infrastructure, by what user or service account and more. The information that Witness gathers while the command is running is down to which [Attestors](docs/attestor.md) are used. Attestors are implementations of an interface that find and assert facts about the system Witness is running on (e.g., [AWS Attestor](docs/attestors/aws-iid.md)). Finally, Witness can compile this information into an [in-toto attestation](https://github.com/in-toto/attestation), place it in a [DSSE Envelope](https://github.com/secure-systems-lab/dsse) and sign that envelope with the key that was supplied by the user.

### Storing
For storage, the Witness project can upload signed attestations to an [Archivista](https://github.com/in-toto/archivista) server, a graph and storage service for in-toto attestations. This enables the discovery and retrieval of attestations for verification of software artifacts.

### Verifying
Witness allows users to verify the attestations that they generate by providing the `witness verify` command. To achieve this, Witness uses a [policy file](./docs/policy.md) defined by the user to check for presence of the expected attestations and that they were signed by the appropriate functionaries (Public keys or roots of trust that are trusted to sign certain types of attestation). To verify the attestation body itself, Witness supports defining [OPA Rego](https://www.openpolicyagent.org/docs/latest/policy-language/) policies inside the policy file. This allows users to ensure the facts asserted by the Attestors are reported expected.

Binary file added docs/assets/demo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/assets/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion docs/attestor.md

This file was deleted.

Loading

0 comments on commit 8962cd8

Please sign in to comment.