Skip to content
This repository has been archived by the owner on May 3, 2022. It is now read-only.

Commit

Permalink
feat: use Canonical JSON (#612)
Browse files Browse the repository at this point in the history
This switches Duffle to use Canonical JSON, which provides JSON ordering
that is conducive to hashing. http://wiki.laptop.org/go/Canonical_JSON

This will increase interoperability with other languages and platforms,
and match the ordering produced by security tools like Notary.

Note that this change does not impact:

- Claims (still stored as regular JSON)
- Drivers (still receive regular JSON)
- Repo (still uses regular JSON)
  • Loading branch information
technosophos authored and radu-matei committed Mar 14, 2019
1 parent f52e8da commit 779c1d3
Show file tree
Hide file tree
Showing 7 changed files with 20 additions and 40 deletions.
1 change: 1 addition & 0 deletions Gopkg.lock

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

5 changes: 4 additions & 1 deletion Gopkg.toml
Expand Up @@ -49,4 +49,7 @@
[prune]
non-go = true
unused-packages = true
go-tests = true
go-tests = true
[[constraint]]
name = "github.com/docker/go"
version = "1.5.1-1"
34 changes: 3 additions & 31 deletions cmd/duffle/create_test.go
Expand Up @@ -44,37 +44,9 @@ func TestCreateCmd(t *testing.T) {
t.Error(err)
}

expected := `{
"name": "test-bundle",
"version": "0.1.0",
"description": "A short description of your bundle",
"keywords": [
"test-bundle",
"cnab",
"tutorial"
],
"maintainers": [
{
"name": "John Doe",
"email": "john.doe@example.com",
"url": "https://example.com"
},
{
"name": "Jane Doe",
"email": "jane.doe@example.com",
"url": "https://example.com"
}
],
"invocationImages": {
"cnab": {
"name": "cnab",
"builder": "docker",
"configuration": {
"registry": "deislabs"
}
}
}
}`
// This is the Canonical JSON representation. http://wiki.laptop.org/go/Canonical_JSON
expected := `{"description":"A short description of your bundle","invocationImages":{"cnab":{"builder":"docker","configuration":{"registry":"deislabs"},"name":"cnab"}},"keywords":["test-bundle","cnab","tutorial"],"maintainers":[{"email":"john.doe@example.com","name":"John Doe","url":"https://example.com"},{"email":"jane.doe@example.com","name":"Jane Doe","url":"https://example.com"}],"name":"test-bundle","version":"0.1.0"}`

if string(mbytes) != expected {
t.Errorf("Expected duffle.json output to look like this:\n\n%s\n\nGot:\n\n%s", expected, string(mbytes))
}
Expand Down
7 changes: 4 additions & 3 deletions pkg/bundle/bundle.go
@@ -1,13 +1,14 @@
package bundle

import (
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"strings"

"github.com/docker/go/canonical/json"
)

// Bundle is a CNAB metadata document
Expand Down Expand Up @@ -40,7 +41,7 @@ func ParseReader(r io.Reader) (Bundle, error) {
// WriteFile serializes the bundle and writes it to a file as JSON.
func (b Bundle) WriteFile(dest string, mode os.FileMode) error {
// FIXME: The marshal here should exactly match the Marshal in the signature code.
d, err := json.MarshalIndent(b, "", " ")
d, err := json.MarshalCanonical(b)
if err != nil {
return err
}
Expand All @@ -49,7 +50,7 @@ func (b Bundle) WriteFile(dest string, mode os.FileMode) error {

// WriteTo writes unsigned JSON to an io.Writer using the standard formatting.
func (b Bundle) WriteTo(w io.Writer) (int64, error) {
d, err := json.MarshalIndent(b, "", " ")
d, err := json.MarshalCanonical(b)
if err != nil {
return 0, err
}
Expand Down
3 changes: 2 additions & 1 deletion pkg/driver/driver.go
@@ -1,9 +1,10 @@
package driver

import (
"encoding/json"
"fmt"
"io"

"github.com/docker/go/canonical/json"
)

// ImageType constants provide some of the image types supported
Expand Down
5 changes: 3 additions & 2 deletions pkg/duffle/manifest/create.go
@@ -1,11 +1,12 @@
package manifest

import (
"encoding/json"
"io/ioutil"
"os"
"path/filepath"

"github.com/docker/go/canonical/json"

"github.com/deislabs/duffle/pkg/bundle"
)

Expand Down Expand Up @@ -62,7 +63,7 @@ func Scaffold(path string) error {
},
}

d, err := json.MarshalIndent(m, "", " ")
d, err := json.MarshalCanonical(m)
if err != nil {
return err
}
Expand Down
5 changes: 3 additions & 2 deletions pkg/signature/signature.go
Expand Up @@ -3,10 +3,11 @@ package signature
import (
"bytes"
"crypto"
"encoding/json"
"errors"
"io"

"github.com/docker/go/canonical/json"

"golang.org/x/crypto/openpgp"
"golang.org/x/crypto/openpgp/armor"
"golang.org/x/crypto/openpgp/clearsign"
Expand Down Expand Up @@ -129,7 +130,7 @@ func (s *Signer) prepareSign(b *bundle.Bundle) (*packet.PrivateKey, []byte, erro

// We want a canonical representation of a serialized bundle, which is why we
// take the object.
data, err := json.MarshalIndent(b, "", " ")
data, err := json.MarshalCanonical(b)
if err != nil {
return pk, res, err
}
Expand Down

0 comments on commit 779c1d3

Please sign in to comment.