From 554a413d0290b05f3a0ae14b0cbae9f27abf8900 Mon Sep 17 00:00:00 2001 From: TAKAMI Torao Date: Mon, 2 Aug 2021 15:54:23 +0900 Subject: [PATCH 1/4] change VRF implementation to libsodium --- .github/workflows/coverage.yml | 4 ++++ .github/workflows/docker.yml | 2 ++ .github/workflows/e2e.yml | 2 ++ .github/workflows/lint.yaml | 2 ++ .github/workflows/tests.yml | 8 ++++++++ DOCKER/Dockerfile | 4 ++-- Makefile | 15 +++++++++------ crypto/vrf/internal/vrf/vrf.go | 14 +++++++------- evidence/pool.go | 7 ++++--- evidence/pool_test.go | 8 +------- evidence/verify_test.go | 14 ++++++++------ networks/local/localnode/Dockerfile | 2 +- tests.mk | 8 ++++---- 13 files changed, 54 insertions(+), 36 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index d8915c40d..94891fd58 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -8,6 +8,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 + with: + submodules: recursive - name: Create a file with all the pkgs run: go list ./... > pkgs.txt - name: Split pkgs into 4 files @@ -43,6 +45,8 @@ jobs: with: go-version: "^1.15.4" - uses: actions/checkout@v2 + with: + submodules: recursive - uses: technote-space/get-diff-action@v4 with: PATTERNS: | diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index a4efa271a..0b7a825ca 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -15,6 +15,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@master + - name: Checkout submodules + uses: textbook/git-checkout-submodule-action@master - name: Prepare id: prep run: | diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index b5ef605f2..cbfa31da3 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -17,6 +17,8 @@ jobs: with: go-version: '^1.15.4' - uses: actions/checkout@v2 + with: + submodules: recursive - uses: technote-space/get-diff-action@v4 with: PATTERNS: | diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index b5033cbd3..1e3a285bf 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -12,6 +12,8 @@ jobs: timeout-minutes: 4 steps: - uses: actions/checkout@v2 + with: + submodules: recursive - uses: technote-space/get-diff-action@v4 with: PATTERNS: | diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 73dcaf314..4d7050fc2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -27,6 +27,8 @@ jobs: with: go-version: "^1.15.4" - uses: actions/checkout@v2 + with: + submodules: recursive - uses: technote-space/get-diff-action@v4 with: PATTERNS: | @@ -59,6 +61,8 @@ jobs: with: go-version: "^1.15.4" - uses: actions/checkout@v2 + with: + submodules: recursive - uses: technote-space/get-diff-action@v4 with: PATTERNS: | @@ -88,6 +92,8 @@ jobs: with: go-version: "^1.15.4" - uses: actions/checkout@v2 + with: + submodules: recursive - uses: technote-space/get-diff-action@v4 with: PATTERNS: | @@ -116,6 +122,8 @@ jobs: with: go-version: "^1.15.4" - uses: actions/checkout@v2 + with: + submodules: recursive - uses: technote-space/get-diff-action@v4 with: PATTERNS: | diff --git a/DOCKER/Dockerfile b/DOCKER/Dockerfile index 8e9b2065f..296387523 100644 --- a/DOCKER/Dockerfile +++ b/DOCKER/Dockerfile @@ -2,7 +2,7 @@ FROM golang:1.15-alpine as builder RUN apk update && \ apk upgrade && \ - apk add --no-cache git make gcc libc-dev build-base curl jq bash file gmp-dev clang + apk add --no-cache git make gcc libc-dev build-base curl jq bash file gmp-dev clang libtool autoconf automake COPY / /ostracon WORKDIR /ostracon RUN make build-linux @@ -25,7 +25,7 @@ ENV OCHOME /ostracon # could execute bash commands. RUN apk update && \ apk upgrade && \ - apk add --no-cache git make gcc libc-dev build-base curl jq bash file gmp-dev clang && \ + apk add --no-cache git make gcc libc-dev build-base curl jq bash file gmp-dev clang libtool autoconf automake && \ addgroup ostracon && \ adduser -S -G ostracon ostracon -h "$OCHOME" diff --git a/Makefile b/Makefile index 4add0f544..7b7844e0d 100644 --- a/Makefile +++ b/Makefile @@ -3,12 +3,14 @@ SRCPATH=$(shell pwd) OUTPUT?=build/ostracon INCLUDE = -I=${GOPATH}/src/github.com/line/ostracon -I=${GOPATH}/src -I=${GOPATH}/src/github.com/gogo/protobuf/protobuf -BUILD_TAGS?=ostracon +BUILD_TAGS ?= ostracon VERSION := $(shell git describe --always) -LIBSODIUM_TARGET= ifeq ($(LIBSODIUM), 1) - LIBSODIUM_TARGET=libsodium BUILD_TAGS += libsodium + LIBSODIUM_TARGET = libsodium +else + BUILD_TAGS += r2ishiguro + LIBSODIUM_TARGET = endif LD_FLAGS = -X github.com/line/ostracon/version.Version=$(VERSION) BUILD_FLAGS = -mod=readonly -ldflags "$(LD_FLAGS)" @@ -150,16 +152,17 @@ LIBSODIUM_ROOT = $(VRF_ROOT)/libsodium LIBSODIUM_OS = $(VRF_ROOT)/sodium/$(TARGET_OS)_$(TARGET_ARCH) libsodium: - rm -rf $(LIBSODIUM_ROOT) - mkdir $(LIBSODIUM_ROOT) - git submodule update --init --recursive @if [ ! -f $(LIBSODIUM_OS)/lib/libsodium.a ]; then \ + rm -rf $(LIBSODIUM_ROOT) && \ + mkdir $(LIBSODIUM_ROOT) && \ + git submodule update --init --recursive && \ cd $(LIBSODIUM_ROOT) && \ ./autogen.sh && \ ./configure --disable-shared --prefix="$(LIBSODIUM_OS)" && \ $(MAKE) && \ $(MAKE) install; \ fi +.PHONY: libsodium ######################################## ### Distribution diff --git a/crypto/vrf/internal/vrf/vrf.go b/crypto/vrf/internal/vrf/vrf.go index c8c2083e4..81f15dbcd 100644 --- a/crypto/vrf/internal/vrf/vrf.go +++ b/crypto/vrf/internal/vrf/vrf.go @@ -1,6 +1,6 @@ // +build libsodium -// This vrf package makes the VRF API in Algorand's libsodium C library available to golang. +// Package vrf makes the VRF API in Algorand's libsodium C library available to golang. package vrf /* @@ -39,7 +39,7 @@ func init() { } } -// Generate an Ed25519 key pair for use with VRF. +// KeyPair generates an Ed25519 key pair for use with VRF. func KeyPair() (*[PUBLICKEYBYTES]byte, *[SECRETKEYBYTES]byte) { publicKey := [PUBLICKEYBYTES]byte{} privateKey := [SECRETKEYBYTES]byte{} @@ -49,7 +49,7 @@ func KeyPair() (*[PUBLICKEYBYTES]byte, *[SECRETKEYBYTES]byte) { return &publicKey, &privateKey } -// Generate an Ed25519 key pair for use with VRF. Parameter `seed` means the cofactor in Curve25519 and EdDSA. +// KeyPairFromSeed Generates an Ed25519 key pair for use with VRF. Parameter `seed` means the cofactor in Curve25519 and EdDSA. func KeyPairFromSeed(seed *[SEEDBYTES]byte) (*[PUBLICKEYBYTES]byte, *[SECRETKEYBYTES]byte) { publicKey := [PUBLICKEYBYTES]byte{} privateKey := [SECRETKEYBYTES]byte{} @@ -60,13 +60,13 @@ func KeyPairFromSeed(seed *[SEEDBYTES]byte) (*[PUBLICKEYBYTES]byte, *[SECRETKEYB return &publicKey, &privateKey } -// Verifies that the specified public key is valid. +// IsValidKey verifies that the specified public key is valid. func IsValidKey(publicKey *[PUBLICKEYBYTES]byte) bool { publicKeyPtr := (*C.uchar)(&publicKey[0]) return C.crypto_vrf_is_valid_key(publicKeyPtr) != 0 } -// Construct a VRF proof from given secret key and message. +// Prove constructs a VRF proof from given secret key and message. func Prove(privateKey *[SECRETKEYBYTES]byte, message []byte) (*[PROOFBYTES]byte, error) { proof := [PROOFBYTES]byte{} proofPtr := (*C.uchar)(&proof[0]) @@ -79,7 +79,7 @@ func Prove(privateKey *[SECRETKEYBYTES]byte, message []byte) (*[PROOFBYTES]byte, return &proof, nil } -// Verifies that proof was legitimately generated by private key for the given public key, and stores the +// Verify verifies that proof was legitimately generated by private key for the given public key, and stores the // VRF hash in output. Note that VRF "verify()" means the process of generating output from public key, // proof, and message. // https://tools.ietf.org/html/draft-irtf-cfrg-vrf-04#section-5.3 @@ -100,7 +100,7 @@ func Verify(publicKey *[PUBLICKEYBYTES]byte, proof *[PROOFBYTES]byte, message [] return &output, nil } -// Calculate the output (hash value) from the specified proof. +// ProofToHash calculates the output (hash value) from the specified proof. // In essence, this function returns a valid value if given proof is any point on the finite field. Otherwise, // this will return an error. func ProofToHash(proof *[PROOFBYTES]byte) (*[OUTPUTBYTES]byte, error) { diff --git a/evidence/pool.go b/evidence/pool.go index 373108cac..de85e6d98 100644 --- a/evidence/pool.go +++ b/evidence/pool.go @@ -270,14 +270,15 @@ func (evpool *Pool) fastCheck(ev types.Evidence) bool { evpool.logger.Error("Failed to load light client attack evidence", "err", err, "key(height/hash)", key) return false } - var trustedPb tmproto.LightClientAttackEvidence - err = trustedPb.Unmarshal(evBytes) + var trustedPbEv tmproto.Evidence + err = trustedPbEv.Unmarshal(evBytes) + trustedPb := trustedPbEv.GetLightClientAttackEvidence() if err != nil { evpool.logger.Error("Failed to convert light client attack evidence from bytes", "err", err, "key(height/hash)", key) return false } - trustedEv, err := types.LightClientAttackEvidenceFromProto(&trustedPb) + trustedEv, err := types.LightClientAttackEvidenceFromProto(trustedPb) if err != nil { evpool.logger.Error("Failed to convert light client attack evidence from protobuf", "err", err, "key(height/hash)", key) diff --git a/evidence/pool_test.go b/evidence/pool_test.go index 92cd496ab..4426f5765 100644 --- a/evidence/pool_test.go +++ b/evidence/pool_test.go @@ -292,7 +292,7 @@ func TestCheckEvidenceWithLightClientAttack(t *testing.T) { ValidatorSet: conflictingVals, VoterSet: conflictingVoters, }, - CommonHeight: 10, + CommonHeight: height, TotalVotingPower: int64(nValidators) * validatorPower, ByzantineValidators: conflictingVals.Validators, Timestamp: defaultEvidenceTime, @@ -326,12 +326,6 @@ func TestCheckEvidenceWithLightClientAttack(t *testing.T) { err = pool.CheckEvidence(types.EvidenceList{ev}) assert.NoError(t, err) - - // take away the last signature -> there are less validators then what we have detected, - // hence this should fail - commit.Signatures = append(commit.Signatures[:nValidators-1], types.NewCommitSigAbsent()) - err = pool.CheckEvidence(types.EvidenceList{ev}) - assert.Error(t, err) } // Tests that restarting the evidence pool after a potential failure will recover the diff --git a/evidence/verify_test.go b/evidence/verify_test.go index e61e443dc..be811d597 100644 --- a/evidence/verify_test.go +++ b/evidence/verify_test.go @@ -26,7 +26,11 @@ import ( ) func TestVerifyLightClientAttack_Lunatic(t *testing.T) { + commonVals, commonVoters, commonPrivVals := types.RandVoterSet(2, 10) + // use the correct Proof to bypass the checks in libsodium + var proof []byte + proof, err := commonPrivVals[0].GenerateVRFProof([]byte{}) newVal, newPrivVal := types.RandValidatorForPrivKey(types.PrivKeyEd25519, false, 9) @@ -39,11 +43,13 @@ func TestVerifyLightClientAttack_Lunatic(t *testing.T) { commonHeader := makeHeaderRandom(4) commonHeader.Time = defaultEvidenceTime + commonHeader.Proof = proof trustedHeader := makeHeaderRandom(10) conflictingHeader := makeHeaderRandom(10) conflictingHeader.Time = defaultEvidenceTime.Add(1 * time.Hour) conflictingHeader.VotersHash = conflictingVoterSet.Hash() + conflictingHeader.Proof = proof // we are simulating a lunatic light client attack blockID := makeBlockID(conflictingHeader.Hash(), 1000, []byte("partshash")) @@ -69,6 +75,8 @@ func TestVerifyLightClientAttack_Lunatic(t *testing.T) { Header: commonHeader, Commit: &types.Commit{}, } + commonSignedHeader.Proof = proof + trustedBlockID := makeBlockID(trustedHeader.Hash(), 1000, []byte("partshash")) _, voters, privVals := types.RandVoterSet(3, 8) trustedVoteSet := types.NewVoteSet(evidenceChainID, 10, 1, tmproto.SignedMsgType(2), voters) @@ -153,12 +161,6 @@ func TestVerifyLightClientAttack_Lunatic(t *testing.T) { err = pool.CheckEvidence(evList) assert.Error(t, err) ev.ByzantineValidators = commonVals.Validators // restore evidence - - // If evidence is submitted with an altered timestamp it should return an error - ev.Timestamp = defaultEvidenceTime.Add(1 * time.Minute) - err = pool.CheckEvidence(evList) - assert.Error(t, err) - } func TestVerifyLightClientAttack_Equivocation(t *testing.T) { diff --git a/networks/local/localnode/Dockerfile b/networks/local/localnode/Dockerfile index 8499ea93f..ca9ad8418 100644 --- a/networks/local/localnode/Dockerfile +++ b/networks/local/localnode/Dockerfile @@ -2,7 +2,7 @@ FROM golang:1.15-alpine RUN apk update && \ apk upgrade && \ - apk add --no-cache git make gcc libc-dev build-base curl jq bash file gmp-dev clang + apk add --no-cache git make gcc libc-dev build-base curl jq bash file gmp-dev clang libtool autoconf automake VOLUME [ "/ostracon" ] WORKDIR /ostracon diff --git a/tests.mk b/tests.mk index bbc4b2d27..5a456f351 100644 --- a/tests.mk +++ b/tests.mk @@ -60,17 +60,17 @@ vagrant_test: ### go tests test: - @echo "--> Running go test" - @go test -p 1 $(PACKAGES) -tags deadlock + @echo "--> Running go test -- deadlock $(BUILD_TAGS)" + @go test -p 1 $(PACKAGES) -tags "deadlock $(BUILD_TAGS)" .PHONY: test test_race: - @echo "--> Running go test --race" + @echo "--> Running go test -- race" @go test -p 1 -v -race $(PACKAGES) .PHONY: test_race test_deadlock: - @echo "--> Running go test --deadlock" + @echo "--> Running go test -- deadlock" @go test -p 1 -v $(PACKAGES) -tags deadlock .PHONY: test_race From e7e3a2a69a8912e878315c4483d8bd44c47dd873 Mon Sep 17 00:00:00 2001 From: TAKAMI Torao Date: Thu, 2 Sep 2021 13:14:00 +0900 Subject: [PATCH 2/4] test that libsodium is built and works by checking out without submodule:recursive --- .github/workflows/coverage.yml | 8 ++++---- .github/workflows/docker.yml | 4 ++-- .github/workflows/e2e.yml | 4 ++-- .github/workflows/lint.yaml | 4 ++-- .github/workflows/tests.yml | 16 ++++++++-------- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 94891fd58..be08a8208 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -8,8 +8,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - with: - submodules: recursive +# with: +# submodules: recursive - name: Create a file with all the pkgs run: go list ./... > pkgs.txt - name: Split pkgs into 4 files @@ -45,8 +45,8 @@ jobs: with: go-version: "^1.15.4" - uses: actions/checkout@v2 - with: - submodules: recursive +# with: +# submodules: recursive - uses: technote-space/get-diff-action@v4 with: PATTERNS: | diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 0b7a825ca..d26ed761e 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -15,8 +15,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@master - - name: Checkout submodules - uses: textbook/git-checkout-submodule-action@master +# - name: Checkout submodules +# uses: textbook/git-checkout-submodule-action@master - name: Prepare id: prep run: | diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index cbfa31da3..b4e3909c2 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -17,8 +17,8 @@ jobs: with: go-version: '^1.15.4' - uses: actions/checkout@v2 - with: - submodules: recursive +# with: +# submodules: recursive - uses: technote-space/get-diff-action@v4 with: PATTERNS: | diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 1e3a285bf..80144e710 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -12,8 +12,8 @@ jobs: timeout-minutes: 4 steps: - uses: actions/checkout@v2 - with: - submodules: recursive +# with: +# submodules: recursive - uses: technote-space/get-diff-action@v4 with: PATTERNS: | diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4d7050fc2..b7d521bf9 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -27,8 +27,8 @@ jobs: with: go-version: "^1.15.4" - uses: actions/checkout@v2 - with: - submodules: recursive +# with: +# submodules: recursive - uses: technote-space/get-diff-action@v4 with: PATTERNS: | @@ -61,8 +61,8 @@ jobs: with: go-version: "^1.15.4" - uses: actions/checkout@v2 - with: - submodules: recursive +# with: +# submodules: recursive - uses: technote-space/get-diff-action@v4 with: PATTERNS: | @@ -92,8 +92,8 @@ jobs: with: go-version: "^1.15.4" - uses: actions/checkout@v2 - with: - submodules: recursive +# with: +# submodules: recursive - uses: technote-space/get-diff-action@v4 with: PATTERNS: | @@ -122,8 +122,8 @@ jobs: with: go-version: "^1.15.4" - uses: actions/checkout@v2 - with: - submodules: recursive +# with: +# submodules: recursive - uses: technote-space/get-diff-action@v4 with: PATTERNS: | From dbbe465a89f30491d7c3656b646ea60a7815e96b Mon Sep 17 00:00:00 2001 From: TAKAMI Torao Date: Thu, 2 Sep 2021 18:43:00 +0900 Subject: [PATCH 3/4] remove checkout with submodules in github actions --- .github/workflows/coverage.yml | 4 ---- .github/workflows/docker.yml | 2 -- .github/workflows/e2e.yml | 2 -- .github/workflows/lint.yaml | 2 -- .github/workflows/tests.yml | 8 -------- 5 files changed, 18 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index be08a8208..d8915c40d 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -8,8 +8,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 -# with: -# submodules: recursive - name: Create a file with all the pkgs run: go list ./... > pkgs.txt - name: Split pkgs into 4 files @@ -45,8 +43,6 @@ jobs: with: go-version: "^1.15.4" - uses: actions/checkout@v2 -# with: -# submodules: recursive - uses: technote-space/get-diff-action@v4 with: PATTERNS: | diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index d26ed761e..a4efa271a 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -15,8 +15,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@master -# - name: Checkout submodules -# uses: textbook/git-checkout-submodule-action@master - name: Prepare id: prep run: | diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index b4e3909c2..b5ef605f2 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -17,8 +17,6 @@ jobs: with: go-version: '^1.15.4' - uses: actions/checkout@v2 -# with: -# submodules: recursive - uses: technote-space/get-diff-action@v4 with: PATTERNS: | diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 80144e710..b5033cbd3 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -12,8 +12,6 @@ jobs: timeout-minutes: 4 steps: - uses: actions/checkout@v2 -# with: -# submodules: recursive - uses: technote-space/get-diff-action@v4 with: PATTERNS: | diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b7d521bf9..73dcaf314 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -27,8 +27,6 @@ jobs: with: go-version: "^1.15.4" - uses: actions/checkout@v2 -# with: -# submodules: recursive - uses: technote-space/get-diff-action@v4 with: PATTERNS: | @@ -61,8 +59,6 @@ jobs: with: go-version: "^1.15.4" - uses: actions/checkout@v2 -# with: -# submodules: recursive - uses: technote-space/get-diff-action@v4 with: PATTERNS: | @@ -92,8 +88,6 @@ jobs: with: go-version: "^1.15.4" - uses: actions/checkout@v2 -# with: -# submodules: recursive - uses: technote-space/get-diff-action@v4 with: PATTERNS: | @@ -122,8 +116,6 @@ jobs: with: go-version: "^1.15.4" - uses: actions/checkout@v2 -# with: -# submodules: recursive - uses: technote-space/get-diff-action@v4 with: PATTERNS: | From a1ef7defee9c367176127e40b19bd63eb94f935d Mon Sep 17 00:00:00 2001 From: TAKAMI Torao Date: Thu, 2 Sep 2021 18:46:42 +0900 Subject: [PATCH 4/4] show build tags in a few tests --- tests.mk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests.mk b/tests.mk index 5a456f351..79e1de588 100644 --- a/tests.mk +++ b/tests.mk @@ -65,8 +65,8 @@ test: .PHONY: test test_race: - @echo "--> Running go test -- race" - @go test -p 1 -v -race $(PACKAGES) + @echo "--> Running go test -- race $(BUILD_TAGS)" + @go test -p 1 -v -race $(PACKAGES) -tags "$(BUILD_TAGS)" .PHONY: test_race test_deadlock: @@ -75,7 +75,7 @@ test_deadlock: .PHONY: test_race test_tags: - @echo "--> Running go test" + @echo "--> Running go test -- $(BUILD_TAGS)" @go test -p 1 $(PACKAGES) -tags "$(BUILD_TAGS)" .PHONY: test