From e5c68f97dfbb7dc2677e891ceea9a8eafe42ddb4 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Fri, 19 Jul 2024 23:21:40 +0800 Subject: [PATCH 1/5] docs: update docs for release process (#193) Signed-off-by: Shiwei Zhang --- .gitignore | 3 +++ .vscode/settings.json | 5 ----- release-checklist.md | 24 +++++++++++------------- release-management.md | 37 +++++++++++++++++++------------------ 4 files changed, 33 insertions(+), 36 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.gitignore b/.gitignore index 4d0f184..b04f6b0 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,6 @@ vendor/ .DS_Store /cose-fuzz.zip /workdir/ + +# Editor files +.vscode/ diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index ad24d8c..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "cSpell.words": [ - "supermajority" - ] -} \ No newline at end of file diff --git a/release-checklist.md b/release-checklist.md index abbbf48..fb09d26 100644 --- a/release-checklist.md +++ b/release-checklist.md @@ -6,20 +6,18 @@ This document describes the checklist to publish a release via GitHub workflow. The maintainers may periodically update this checklist based on feedback. -NOTE: Make sure the dependencies in `go.mod` file are expected by the release. -For example, if there are dependencies on certain version of notation library (notation-go or notation-core-go) or ORAS library (oras-go), make sure that version of library is released first, and the version number is updated accordingly in `go.mod` file. -After updating go.mod file, run `go mod tidy` to ensure the go.sum file is also updated with any potential changes. +> [!NOTE] +> Make sure the dependencies in `go.mod` file are expected by the release. +> After updating `go.mod` file, run `go mod tidy` to ensure the `go.sum` file is also updated with any potential changes. ## Release Process -1. Determine a [SemVer2](https://semver.org/)-valid version prefixed with the letter `v` for release. -For example, `version="v1.0.0-alpha.1"`. -1. Bump up the `Version` in [internal/version/version.go](internal/version/version.go#L5) and open a PR for the changes. -1. Wait for the PR merge. -1. Be on the main branch connected to the actual repository (not a fork) and `git pull`. -Ensure `git log -1` shows the latest commit on the main branch. -1. Create a tag `git tag -am $version $version` -1. `git tag` and ensure the name in the list added looks correct, then push the tag directly to the repository by `git push --follow-tags`. -1. Wait for the completion of the GitHub action [release-github](https://github.com/veraison/go-cose/blob/main/.github/workflows/ci.yml). -1. Check the new draft release, revise the release description, and publish the release. +1. Determine a [SemVer2](https://semver.org/)-valid version prefixed with the letter `v` for release. For example, `v1.0.0-alpha.1`. +1. Determine the commit to be tagged and released. +1. Create an issue for voting with title similar to `vote: tag v1.0.0-alpha.1` with the proposed commit. +1. Wait for the vote pass. +1. Cut a release branch `release-X.Y` (e.g. `release-1.0`) if it does not exist. The voted commit MUST be the head of the release branch. + - To cut a release branch directly on GitHub, navigate to `https://github.com/veraison/go-cose/tree/{commit}` and then follow the [creating a branch](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-and-deleting-branches-within-your-repository#creating-a-branch-using-the-branch-dropdown) doc. +1. Draft a new release from the release branch by following the [creating a release](https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository#creating-a-release) doc. Set release title to the voted version and create a tag in the **Choose a tag** dropdown menu with the voted version as the tag name. +1. Proofread the draft release, and publish the release. 1. Announce the release in the community. diff --git a/release-management.md b/release-management.md index 4d66ce0..6c123bf 100644 --- a/release-management.md +++ b/release-management.md @@ -14,31 +14,32 @@ The maintainers may periodically update this policy based on feedback. ## Release Versioning -Consumers of the go-cose project may build directly from main, or pull from released builds. -Builds from main must reference the git-commit as the version: `v1.0.0-2300d5c` +Consumers of the go-cose module may reference `main` directly, or reference released tags. All go-cose [releases][releases] follow a go-lang flavored derivation (`v*`) of the [semver][sem-ver] format, with optional pre-release labels. -Logical Progression of a release: `v1.0.0-2300d5c` --> `v1.0.0-alpha.1` --> `v1.0.0-alpha.2` --> `v1.0.0-rc.1` --> `v1.0.0` +Logical Progression of a release: `v1.0.0-alpha.1` --> `v1.0.0-alpha.2` --> `v1.0.0-rc.1` --> `v1.0.0` -A new major or minor release will not have an automated build/release posted until the branch reaches alpha quality. +A new major or minor release will not have an automated release posted until the branch reaches alpha quality. -- all versions use a preface of `v` -- `X` is the [Major](#major-releases) version -- `Y` is the [Minor](#minor-releases) version -- `Z` is the [Patch](#patch-releases) version +- All versions use a preface of `v` +- Given a version `vX.Y.Z`, + - `X` is the [Major](#major-releases) version + - `Y` is the [Minor](#minor-releases) version + - `Z` is the [Patch](#patch-releases) version - _Optional_ `-alpha.n` | `-rc.n` [pre-release](#pre-release) version - Each incremental alpha or rc build will bump the suffix (`n`) number. - It's not expected to have more than 9 alphas or rcs. The suffix will be a single digit. - If > 9 builds do occur, the format will simply use two digit indicators (`v1.0.0-alpha.10`) -_**Note**: Pre-releases will NOT use the github pre-release flag._ +> [!IMPORTANT] +> Pre-releases will NOT use the github pre-release flag. ## Branch Management To meet the projects stability goals, go-cose does not currently operate with multiple feature branches. -All active development happens in main. +All active development happens in `main`. For each release, a branch is created for servicing, following the versioning name. `v1.0.0-alpha-1` would have an associated [v1.0.0-alpha.1](https://github.com/veraison/go-cose/tree/v1.0.0-alpha.1) branch. All version and branch names are lower case. @@ -76,14 +77,14 @@ Principals of a patch release: - No breaking changes. - No feature or surface area changes. - A "bug fix" that may be a breaking change may require a major release. -- Applicable fixes, including security fixes, may be cherry-picked from main into the latest supported minor release-X.Y branches. -- Patch releases are cut from a release-X.Y.Z branch. +- Applicable fixes, including security fixes, may be cherry-picked from main into the latest supported minor `release-X.Y` branches. +- Patch releases are cut from a `release-X.Y` branch. Each patch release will go through one or more `-alpha.n` and `-rc.n` pre-release phases. ### Pre-Release -As builds of main become stable, and a pending release is planned, a pre-release build will be made. +As builds of `main` become stable, and a pending release is planned, a pre-release build will be made. Pre-releases go through one or more `-alpha.n` releases, followed by one or more incremental `-rc.n` releases. - **alpha.n:** `X.Y.Z-alpha.n` @@ -91,15 +92,15 @@ Pre-releases go through one or more `-alpha.n` releases, followed by one or more To minimize branch management, no additional branches are maintained for each incremental release. - Considered an unstable release which should only be used for early development purposes. - Released incrementally until no additional issues and prs are made against the release. - - Once no triaged issues or pull requests (prs) are scoped to the release, a release candidate (rc) is cut. + - Once no triaged issues or pull requests (prs) are scoped to the release, a release candidate (`rc`) is cut. - To minimize confusion, and the risk of an alpha being widely deployed, alpha branches and released binaries may be removed at the discretion, and a [two-thirds supermajority][super-majority] vote, of the maintainers. Maintainers will create an Issue, and vote upon it for transparency to the decision to remove a release and/or branch. - Not [supported](#supported-releases) - **rc.n:** `X.Y.Z-rc.n` - Released as needed before a final version is released - Bugfixes on new features only as reported through usage - - An rc is not expected to revert to an alpha release. - - Once no triaged issues or prs are scoped to the release, an final version is cut. + - An `rc` is not expected to revert to an alpha release. + - Once no triaged issues or PRs are scoped to the release, an final version is cut. - A release candidate will typically have at least two weeks of bake time, providing the community time to provide feedback. - Release candidates are cut from the branch where the work is done. - To minimize confusion, and the risk of an rc being widely deployed, rc branches and released binaries may be removed at the discretion, and a [two-thirds supermajority][super-majority] vote, of the maintainers. @@ -108,9 +109,9 @@ Maintainers will create an Issue, and vote upon it for transparency to the decis ## Supported Releases -The go-cose maintainers expect to "support" n (current) and n-1 major.minor releases. +The go-cose maintainers expect to "support" n (current) and `n-1` major.minor releases. "Support" means we expect users to be running that version in production. -For example, when v1.3.0 comes out, v1.1.x will no longer be supported for patches, and the maintainers encourage users to upgrade to a supported version as soon as possible. +For example, when `v1.3.0` comes out, `v1.1.x` will no longer be supported for patches, and the maintainers encourage users to upgrade to a supported version as soon as possible. Support will be provided best effort by the maintainers via GitHub issues and pull requests from the community. The go-cose maintainers expect users to stay up-to-date with the versions of go-cose release they use in production, but understand that it may take time to upgrade. From fec747220651273fafb750aca37b8735034b72f2 Mon Sep 17 00:00:00 2001 From: Steve Lasker Date: Fri, 19 Jul 2024 09:40:43 -0700 Subject: [PATCH 2/5] Update Current Release & Pre-release Info (#191) Signed-off-by: steve lasker Co-authored-by: Orie Steele --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0de72d3..5eb1fef 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,9 @@ A golang library for the [COSE specification][cose-spec] ## Project Status -**Current Release**: [go-cose v1.1.0][current-release] +**Current Supported Release**: [go-cose v1.1.0][current-release] + +**Current Pre-Release**: [go-cose v1.3.0-alpha.1][current-pre-release] The project was *initially* forked from the upstream [mozilla-services/go-cose][mozilla-go-cose] project, however the Veraison and Mozilla maintainers have agreed to retire the mozilla-services/go-cose project and focus on [veraison/go-cose][veraison-go-cose] as the active project. @@ -244,3 +246,4 @@ go test -fuzz=FuzzSign1 [mozilla-go-cose]: http://github.com/mozilla-services/go-cose [veraison-go-cose]: https://github.com/veraison/go-cose [current-release]: https://github.com/veraison/go-cose/releases/tag/v1.1.0 +[current-pre-release]: https://github.com/veraison/go-cose/releases/tag/v1.3.0-alpha.1 \ No newline at end of file From 49d22c7548d5cd258422ef875398c62f4a5d9239 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Fri, 16 Aug 2024 00:12:33 +0800 Subject: [PATCH 3/5] build: fix codecov (#200) Signed-off-by: Shiwei Zhang --- .github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8e8e9e6..b32ca9c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,4 +22,6 @@ jobs: - name: Run tests run: go test -race -v -coverprofile=coverage.txt . - name: Upload coverage to codecov.io - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} From 741bc2882f90bfc3f2aafa1e161a21d69f0a9ac5 Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 14 Sep 2024 03:32:20 +1200 Subject: [PATCH 4/5] chore: go fmt (#201) Signed-off-by: Alex Richards --- .gitignore | 1 + bench_test.go | 180 +++++++++++++++++++++++++------------------------- 2 files changed, 91 insertions(+), 90 deletions(-) diff --git a/.gitignore b/.gitignore index b04f6b0..9a26cee 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ vendor/ # Editor files .vscode/ +.idea/ diff --git a/bench_test.go b/bench_test.go index 9a95f96..a60d1aa 100644 --- a/bench_test.go +++ b/bench_test.go @@ -1,90 +1,90 @@ -package cose_test - -import ( - "io" - "testing" - - "github.com/veraison/go-cose" -) - -func newSign1Message() *cose.Sign1Message { - return &cose.Sign1Message{ - Headers: cose.Headers{ - Protected: cose.ProtectedHeader{ - cose.HeaderLabelAlgorithm: cose.AlgorithmES256, - }, - Unprotected: cose.UnprotectedHeader{ - cose.HeaderLabelKeyID: []byte{0x01}, - }, - }, - Payload: make([]byte, 100), - Signature: make([]byte, 32), - } -} - -type noSigner struct{} - -func (noSigner) Algorithm() cose.Algorithm { - return cose.AlgorithmES256 -} - -func (noSigner) Sign(_ io.Reader, digest []byte) ([]byte, error) { - return digest, nil -} - -func (noSigner) Verify(_, _ []byte) error { - return nil -} - -func BenchmarkSign1Message_MarshalCBOR(b *testing.B) { - msg := newSign1Message() - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - _, err := msg.MarshalCBOR() - if err != nil { - b.Fatal(err) - } - } -} - -func BenchmarkSign1Message_UnmarshalCBOR(b *testing.B) { - data, err := newSign1Message().MarshalCBOR() - if err != nil { - b.Fatal(err) - } - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - var m cose.Sign1Message - err = m.UnmarshalCBOR(data) - if err != nil { - b.Fatal(err) - } - } -} - -func BenchmarkSign1Message_Sign(b *testing.B) { - msg := newSign1Message() - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - msg.Signature = nil - err := msg.Sign(zeroSource{}, nil, noSigner{}) - if err != nil { - b.Fatal(err) - } - } -} - -func BenchmarkSign1Message_Verify(b *testing.B) { - msg := newSign1Message() - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - err := msg.Verify(nil, noSigner{}) - if err != nil { - b.Fatal(err) - } - } -} +package cose_test + +import ( + "io" + "testing" + + "github.com/veraison/go-cose" +) + +func newSign1Message() *cose.Sign1Message { + return &cose.Sign1Message{ + Headers: cose.Headers{ + Protected: cose.ProtectedHeader{ + cose.HeaderLabelAlgorithm: cose.AlgorithmES256, + }, + Unprotected: cose.UnprotectedHeader{ + cose.HeaderLabelKeyID: []byte{0x01}, + }, + }, + Payload: make([]byte, 100), + Signature: make([]byte, 32), + } +} + +type noSigner struct{} + +func (noSigner) Algorithm() cose.Algorithm { + return cose.AlgorithmES256 +} + +func (noSigner) Sign(_ io.Reader, digest []byte) ([]byte, error) { + return digest, nil +} + +func (noSigner) Verify(_, _ []byte) error { + return nil +} + +func BenchmarkSign1Message_MarshalCBOR(b *testing.B) { + msg := newSign1Message() + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := msg.MarshalCBOR() + if err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkSign1Message_UnmarshalCBOR(b *testing.B) { + data, err := newSign1Message().MarshalCBOR() + if err != nil { + b.Fatal(err) + } + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var m cose.Sign1Message + err = m.UnmarshalCBOR(data) + if err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkSign1Message_Sign(b *testing.B) { + msg := newSign1Message() + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + msg.Signature = nil + err := msg.Sign(zeroSource{}, nil, noSigner{}) + if err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkSign1Message_Verify(b *testing.B) { + msg := newSign1Message() + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + err := msg.Verify(nil, noSigner{}) + if err != nil { + b.Fatal(err) + } + } +} From 76892d14a6a65151eb406e7b86b96a34931df1d1 Mon Sep 17 00:00:00 2001 From: Shiwei Zhang Date: Fri, 13 Sep 2024 23:35:35 +0800 Subject: [PATCH 5/5] test: add examples for detached payload (#205) Signed-off-by: Shiwei Zhang --- example_test.go | 135 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/example_test.go b/example_test.go index ffc2482..c941b65 100644 --- a/example_test.go +++ b/example_test.go @@ -78,6 +78,77 @@ func ExampleSignMessage() { // verification error as expected } +// This example demonstrates signing and verifying COSE_Sign signatures with +// detached payload. +// +// The COSE Sign API is EXPERIMENTAL and may be changed or removed in a later +// release. +func ExampleSignMessage_detachedPayload() { + // create a signature holder + sigHolder := cose.NewSignature() + sigHolder.Headers.Protected.SetAlgorithm(cose.AlgorithmES512) + sigHolder.Headers.Unprotected[cose.HeaderLabelKeyID] = []byte("1") + + // create message to be signed + msgToSign := cose.NewSignMessage() + msgToSign.Payload = []byte("hello world") + msgToSign.Signatures = append(msgToSign.Signatures, sigHolder) + + // create a signer + privateKey, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader) + if err != nil { + panic(err) + } + signer, err := cose.NewSigner(cose.AlgorithmES512, privateKey) + if err != nil { + panic(err) + } + + // sign message + err = msgToSign.Sign(rand.Reader, nil, signer) + if err != nil { + panic(err) + } + msgToSign.Payload = nil // detach payload + sig, err := msgToSign.MarshalCBOR() + if err != nil { + panic(err) + } + fmt.Println("message signed") + + // create a verifier from a trusted public key + publicKey := privateKey.Public() + verifier, err := cose.NewVerifier(cose.AlgorithmES512, publicKey) + if err != nil { + panic(err) + } + + // verify message + var msgToVerify cose.SignMessage + err = msgToVerify.UnmarshalCBOR(sig) + if err != nil { + panic(err) + } + msgToVerify.Payload = []byte("hello world") // reattach payload + err = msgToVerify.Verify(nil, verifier) + if err != nil { + panic(err) + } + fmt.Println("message verified") + + // tamper the message and verification should fail + msgToVerify.Payload = []byte("foobar") + err = msgToVerify.Verify(nil, verifier) + if err != cose.ErrVerification { + panic(err) + } + fmt.Println("verification error as expected") + // Output: + // message signed + // message verified + // verification error as expected +} + // This example demonstrates signing and verifying COSE_Sign1 signatures. func ExampleSign1Message() { // create message to be signed @@ -139,6 +210,70 @@ func ExampleSign1Message() { // verification error as expected } +// This example demonstrates signing and verifying COSE_Sign1 signatures with +// detached payload. +func ExampleSign1Message_detachedPayload() { + // create message to be signed + msgToSign := cose.NewSign1Message() + msgToSign.Payload = []byte("hello world") + msgToSign.Headers.Protected.SetAlgorithm(cose.AlgorithmES512) + msgToSign.Headers.Unprotected[cose.HeaderLabelKeyID] = []byte("1") + + // create a signer + privateKey, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader) + if err != nil { + panic(err) + } + signer, err := cose.NewSigner(cose.AlgorithmES512, privateKey) + if err != nil { + panic(err) + } + + // sign message + err = msgToSign.Sign(rand.Reader, nil, signer) + if err != nil { + panic(err) + } + msgToSign.Payload = nil // detach payload + sig, err := msgToSign.MarshalCBOR() + if err != nil { + panic(err) + } + fmt.Println("message signed") + + // create a verifier from a trusted public key + publicKey := privateKey.Public() + verifier, err := cose.NewVerifier(cose.AlgorithmES512, publicKey) + if err != nil { + panic(err) + } + + // verify message + var msgToVerify cose.Sign1Message + err = msgToVerify.UnmarshalCBOR(sig) + if err != nil { + panic(err) + } + msgToVerify.Payload = []byte("hello world") // reattach payload + err = msgToVerify.Verify(nil, verifier) + if err != nil { + panic(err) + } + fmt.Println("message verified") + + // tamper the message and verification should fail + msgToVerify.Payload = []byte("foobar") + err = msgToVerify.Verify(nil, verifier) + if err != cose.ErrVerification { + panic(err) + } + fmt.Println("verification error as expected") + // Output: + // message signed + // message verified + // verification error as expected +} + // This example demonstrates signing COSE_Sign1_Tagged signatures using Sign1(). func ExampleSign1() { // create a signer