diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9b837108..139024d9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,14 +14,14 @@ jobs: name: ci runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - - uses: actions/setup-go@v4 + - uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: go-version: 1.18 - name: lint - uses: golangci/golangci-lint-action@v3 + uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0 - name: test run: make docker && make docker-test diff --git a/cache/instrumented_redis.go b/cache/instrumented_redis.go index c94cff45..9ff759ef 100755 --- a/cache/instrumented_redis.go +++ b/cache/instrumented_redis.go @@ -1,10 +1,10 @@ package cache -// Code generated by gowrap. DO NOT EDIT. -// template: ../.prom-gowrap.tmpl -// gowrap: http://github.com/hexdigest/gowrap +// DO NOT EDIT! +// This code is generated with http://github.com/hexdigest/gowrap tool +// using ../.prom-gowrap.tmpl template -//go:generate gowrap gen -p github.com/brave/go-sync/cache -i RedisClient -t ../.prom-gowrap.tmpl -o instrumented_redis.go -l "" +//go:generate gowrap gen -p github.com/brave/go-sync/cache -i RedisClient -t ../.prom-gowrap.tmpl -o instrumented_redis.go import ( "context" diff --git a/command/command.go b/command/command.go index 2ddba677..57911361 100644 --- a/command/command.go +++ b/command/command.go @@ -25,6 +25,7 @@ const ( setSyncPollInterval int32 = 30 nigoriTypeID int32 = 47745 deviceInfoTypeID int = 154522 + historyTypeID int = 963985 maxActiveDevices int = 50 ) @@ -241,8 +242,21 @@ func handleCommitRequest(cache *cache.Cache, commitMsg *sync_pb.CommitMessage, c } oldVersion := *entityToCommit.Version + isUpdateOp := oldVersion != 0 *entityToCommit.Version = *entityToCommit.Mtime - if oldVersion == 0 { // Create + if *entityToCommit.DataType == historyTypeID { + // Check if item exists using client_unique_tag + isUpdateOp, err = db.HasItem(clientID, *entityToCommit.ClientDefinedUniqueTag) + if err != nil { + log.Error().Err(err).Msg("Insert history sync entity failed") + rspType := sync_pb.CommitResponse_TRANSIENT_ERROR + entryRsp.ResponseType = &rspType + entryRsp.ErrorMessage = aws.String(fmt.Sprintf("Insert history sync entity failed: %v", err.Error())) + continue + } + } + + if !isUpdateOp { // Create if itemCount+count >= maxClientObjectQuota { rspType := sync_pb.CommitResponse_OVER_QUOTA entryRsp.ResponseType = &rspType diff --git a/datastore/datastore.go b/datastore/datastore.go index 9df08d7d..3e240ac2 100644 --- a/datastore/datastore.go +++ b/datastore/datastore.go @@ -25,4 +25,6 @@ type Datastore interface { DisableSyncChain(clientID string) error // IsSyncChainDisabled checks whether a given sync chain is deleted IsSyncChainDisabled(clientID string) (bool, error) + // Checks if sync item exists for a client + HasItem(clientID string, ID string) (bool, error) } diff --git a/datastore/datastoretest/mock_datastore.go b/datastore/datastoretest/mock_datastore.go index 84f99d54..94c889bf 100644 --- a/datastore/datastoretest/mock_datastore.go +++ b/datastore/datastoretest/mock_datastore.go @@ -40,6 +40,11 @@ func (m *MockDatastore) HasServerDefinedUniqueTag(clientID string, tag string) ( return args.Bool(0), args.Error(1) } +func (m *MockDatastore) HasItem(clientID string, ID string) (bool, error) { + args := m.Called(clientID, ID) + return args.Bool(0), args.Error(1) +} + // GetClientItemCount mocks calls to GetClientItemCount func (m *MockDatastore) GetClientItemCount(clientID string) (int, error) { args := m.Called(clientID) diff --git a/datastore/instrumented_datastore.go b/datastore/instrumented_datastore.go index e1c6688d..35709aae 100644 --- a/datastore/instrumented_datastore.go +++ b/datastore/instrumented_datastore.go @@ -1,10 +1,10 @@ package datastore -// Code generated by gowrap. DO NOT EDIT. -// template: ../.prom-gowrap.tmpl -// gowrap: http://github.com/hexdigest/gowrap +// DO NOT EDIT! +// This code is generated with http://github.com/hexdigest/gowrap tool +// using ../.prom-gowrap.tmpl template -//go:generate gowrap gen -p github.com/brave/go-sync/datastore -i Datastore -t ../.prom-gowrap.tmpl -o instrumented_datastore.go -l "" +//go:generate gowrap gen -p github.com/brave/go-sync/datastore -i Datastore -t ../.prom-gowrap.tmpl -o instrumented_datastore.go import ( "time" @@ -93,6 +93,20 @@ func (_d DatastoreWithPrometheus) GetUpdatesForType(dataType int, clientToken in return _d.base.GetUpdatesForType(dataType, clientToken, fetchFolders, clientID, maxSize) } +// HasItem implements Datastore +func (_d DatastoreWithPrometheus) HasItem(clientID string, ID string) (b1 bool, err error) { + _since := time.Now() + defer func() { + result := "ok" + if err != nil { + result = "error" + } + + datastoreDurationSummaryVec.WithLabelValues(_d.instanceName, "HasItem", result).Observe(time.Since(_since).Seconds()) + }() + return _d.base.HasItem(clientID, ID) +} + // HasServerDefinedUniqueTag implements Datastore func (_d DatastoreWithPrometheus) HasServerDefinedUniqueTag(clientID string, tag string) (b1 bool, err error) { _since := time.Now() diff --git a/datastore/sync_entity.go b/datastore/sync_entity.go index 530566f1..2075f607 100644 --- a/datastore/sync_entity.go +++ b/datastore/sync_entity.go @@ -21,13 +21,18 @@ import ( ) const ( - maxBatchGetItemSize = 100 // Limited by AWS. - maxTransactDeleteItemSize = 10 // Limited by AWS. - clientTagItemPrefix = "Client#" - serverTagItemPrefix = "Server#" - conditionalCheckFailed = "ConditionalCheckFailed" - disabledChainID = "disabled_chain" - reasonDeleted = "deleted" + maxBatchGetItemSize = 100 // Limited by AWS. + maxTransactDeleteItemSize = 10 // Limited by AWS. + clientTagItemPrefix = "Client#" + serverTagItemPrefix = "Server#" + conditionalCheckFailed = "ConditionalCheckFailed" + disabledChainID = "disabled_chain" + reasonDeleted = "deleted" + historyTypeID int = 963985 + historyDeleteDirectiveTypeID int = 150251 + // Expiration time for history and history delete directive + // entities in seconds + HistoryExpirationIntervalSecs = 60 * 60 * 24 * 90 // 90 days ) // SyncEntity is used to marshal and unmarshal sync items in dynamoDB. @@ -50,6 +55,7 @@ type SyncEntity struct { ClientDefinedUniqueTag *string `dynamodbav:",omitempty"` UniquePosition []byte `dynamodbav:",omitempty"` DataTypeMtime *string + ExpirationTime *int64 } // SyncEntityByClientIDID implements sort.Interface for []SyncEntity based on @@ -159,7 +165,9 @@ func (dynamo *Dynamo) InsertSyncEntity(entity *SyncEntity) (bool, error) { return false, fmt.Errorf("error building expression to insert sync entity: %w", err) } - if entity.ClientDefinedUniqueTag != nil { + // Write tag item for all data types, except for + // the history type, which does not use tag items. + if entity.ClientDefinedUniqueTag != nil && *entity.DataType != historyTypeID { items := []*dynamodb.TransactWriteItem{} // Additional item for ensuring tag's uniqueness for a specific client. item := NewServerClientUniqueTagItem(entity.ClientID, *entity.ClientDefinedUniqueTag, false) @@ -253,6 +261,28 @@ func (dynamo *Dynamo) HasServerDefinedUniqueTag(clientID string, tag string) (bo return out.Item != nil, nil } +func (dynamo *Dynamo) HasItem(clientID string, ID string) (bool, error) { + primaryKey := PrimaryKey{ClientID: clientID, ID: ID} + key, err := dynamodbattribute.MarshalMap(primaryKey) + + if err != nil { + return false, fmt.Errorf("error marshalling key to check if item existed: %w", err) + } + + input := &dynamodb.GetItemInput{ + Key: key, + ProjectionExpression: aws.String(projPk), + TableName: aws.String(Table), + } + + out, err := dynamo.GetItem(input) + if err != nil { + return false, fmt.Errorf("error calling GetItem to check if item existed: %w", err) + } + + return out.Item != nil, nil +} + // InsertSyncEntitiesWithServerTags is used to insert sync entities with // server-defined unique tags. To ensure the uniqueness, for each sync entity, // we will write a tag item and a sync item. Items for all the entities in the @@ -470,10 +500,12 @@ func (dynamo *Dynamo) UpdateSyncEntity(entity *SyncEntity, oldVersion int64) (bo return false, false, fmt.Errorf("error marshalling key to update sync entity: %w", err) } - // condition to ensure to be update only and the version is matched. - cond := expression.And( - expression.AttributeExists(expression.Name(pk)), - expression.Name("Version").Equal(expression.Value(oldVersion))) + // condition to ensure the request is update only... + cond := expression.AttributeExists(expression.Name(pk)) + // ...and the version matches, if applicable + if *entity.DataType != historyTypeID { + cond = expression.And(cond, expression.Name("Version").Equal(expression.Value(oldVersion))) + } update := expression.Set(expression.Name("Version"), expression.Value(entity.Version)) update = update.Set(expression.Name("Mtime"), expression.Value(entity.Mtime)) @@ -507,7 +539,7 @@ func (dynamo *Dynamo) UpdateSyncEntity(entity *SyncEntity, oldVersion int64) (bo // Soft-delete a sync item with a client tag, use a transaction to delete its // tag item too. - if entity.Deleted != nil && entity.ClientDefinedUniqueTag != nil && *entity.Deleted { + if entity.Deleted != nil && entity.ClientDefinedUniqueTag != nil && *entity.Deleted && *entity.DataType != historyTypeID { pk := PrimaryKey{ ClientID: entity.ClientID, ID: clientTagItemPrefix + *entity.ClientDefinedUniqueTag} tagItemKey, err := dynamodbattribute.MarshalMap(pk) @@ -614,10 +646,12 @@ func (dynamo *Dynamo) GetUpdatesForType(dataType int, clientToken int64, fetchFo expression.Value(dataTypeMtimeUpperBound)) keyCond := expression.KeyAnd(pkCond, skCond) exprs := expression.NewBuilder().WithKeyCondition(keyCond) + if !fetchFolders { // Filter folder entities out if fetchFolder is false. exprs = exprs.WithFilter( expression.Equal(expression.Name("Folder"), expression.Value(false))) } + expr, err := exprs.Build() if err != nil { return false, syncEntities, fmt.Errorf("error building expression to get updates: %w", err) @@ -680,8 +714,21 @@ func (dynamo *Dynamo) GetUpdatesForType(dataType int, clientToken int64, fetchFo if err != nil { return false, syncEntities, fmt.Errorf("error unmarshalling updated sync entities: %w", err) } - sort.Sort(SyncEntityByMtime(syncEntities)) - return hasChangesRemaining, syncEntities, nil + + // filter out any expired items, i.e. history sync entities over 90 days old + nowUnix := time.Now().Unix() + var filteredSyncEntities []SyncEntity + for _, syncEntity := range syncEntities { + if syncEntity.ExpirationTime != nil && *syncEntity.ExpirationTime > 0 { + if *syncEntity.ExpirationTime < nowUnix { + continue + } + } + filteredSyncEntities = append(filteredSyncEntities, syncEntity) + } + + sort.Sort(SyncEntityByMtime(filteredSyncEntities)) + return hasChangesRemaining, filteredSyncEntities, nil } func validatePBEntity(entity *sync_pb.SyncEntity) error { @@ -745,16 +792,29 @@ func CreateDBSyncEntity(entity *sync_pb.SyncEntity, cacheGUID *string, clientID originatorClientItemID = entity.IdString } - now := aws.Int64(utils.UnixMilli(time.Now())) + // The client tag hash must be used as the primary key + // for the history type. + if dataType == historyTypeID { + id = *entity.ClientTagHash + } + + now := time.Now() + + var expirationTime *int64 + if dataType == historyTypeID || dataType == historyDeleteDirectiveTypeID { + expirationTime = aws.Int64(now.Unix() + HistoryExpirationIntervalSecs) + } + + nowMillis := aws.Int64(now.UnixMilli()) // ctime is only used when inserting a new entity, here we use client passed // ctime if it is passed, otherwise, use current server time as the creation // time. When updating, ctime will be ignored later in the query statement. - cTime := now + cTime := nowMillis if entity.Ctime != nil { cTime = entity.Ctime } - dataTypeMtime := strconv.Itoa(dataType) + "#" + strconv.FormatInt(*now, 10) + dataTypeMtime := strconv.Itoa(dataType) + "#" + strconv.FormatInt(*nowMillis, 10) // Set default values on Deleted and Folder attributes for new entities, the // default values are specified by sync.proto protocol. @@ -775,7 +835,7 @@ func CreateDBSyncEntity(entity *sync_pb.SyncEntity, cacheGUID *string, clientID ParentID: entity.ParentIdString, Version: entity.Version, Ctime: cTime, - Mtime: now, + Mtime: nowMillis, Name: entity.Name, NonUniqueName: entity.NonUniqueName, ServerDefinedUniqueTag: entity.ServerDefinedUniqueTag, @@ -788,6 +848,7 @@ func CreateDBSyncEntity(entity *sync_pb.SyncEntity, cacheGUID *string, clientID UniquePosition: uniquePosition, DataType: aws.Int(dataType), DataTypeMtime: aws.String(dataTypeMtime), + ExpirationTime: expirationTime, }, nil } diff --git a/datastore/sync_entity_test.go b/datastore/sync_entity_test.go index 67d134c7..ec040c8f 100644 --- a/datastore/sync_entity_test.go +++ b/datastore/sync_entity_test.go @@ -196,6 +196,46 @@ func (suite *SyncEntityTestSuite) TestHasServerDefinedUniqueTag() { suite.Assert().Equal(hasTag, true) } +func (suite *SyncEntityTestSuite) TestHasItem() { + // Insert entity which will be checked later + entity1 := datastore.SyncEntity{ + ClientID: "client1", + ID: "id1", + Version: aws.Int64(1), + Ctime: aws.Int64(12345678), + Mtime: aws.Int64(12345678), + DataType: aws.Int(123), + Folder: aws.Bool(false), + Deleted: aws.Bool(false), + DataTypeMtime: aws.String("123#12345678"), + Specifics: []byte{1, 2}, + } + entity2 := entity1 + entity2.ClientID = "client2" + entity2.ID = "id2" + + _, err := suite.dynamo.InsertSyncEntity(&entity1) + suite.Require().NoError(err, "InsertSyncEntity should succeed") + _, err = suite.dynamo.InsertSyncEntity(&entity2) + suite.Require().NoError(err, "InsertSyncEntity should succeed") + + hasTag, err := suite.dynamo.HasItem("client1", "id1") + suite.Require().NoError(err, "HasItem should succeed") + suite.Assert().Equal(hasTag, true) + + hasTag, err = suite.dynamo.HasItem("client2", "id2") + suite.Require().NoError(err, "HasItem should succeed") + suite.Assert().Equal(hasTag, true) + + hasTag, err = suite.dynamo.HasItem("client2", "id3") + suite.Require().NoError(err, "HasItem should succeed") + suite.Assert().Equal(hasTag, false) + + hasTag, err = suite.dynamo.HasItem("client3", "id2") + suite.Require().NoError(err, "HasItem should succeed") + suite.Assert().Equal(hasTag, false) +} + func (suite *SyncEntityTestSuite) TestInsertSyncEntitiesWithServerTags() { // Insert with same ClientID and server tag would fail. entity1 := datastore.SyncEntity{ @@ -344,6 +384,56 @@ func (suite *SyncEntityTestSuite) TestUpdateSyncEntity_Basic() { suite.Assert().Equal(syncItems, []datastore.SyncEntity{updateEntity1, updateEntity2, updateEntity3}) } +func (suite *SyncEntityTestSuite) TestUpdateSyncEntity_HistoryType() { + // Insert a history item + entity1 := datastore.SyncEntity{ + ClientID: "client1", + ID: "id1", + Version: aws.Int64(1), + ClientDefinedUniqueTag: aws.String("client_tag1"), + Ctime: aws.Int64(12345678), + Mtime: aws.Int64(12345678), + DataType: aws.Int(963985), + Folder: aws.Bool(false), + Deleted: aws.Bool(false), + DataTypeMtime: aws.String("123#12345678"), + Specifics: []byte{1, 2}, + } + conflict, err := suite.dynamo.InsertSyncEntity(&entity1) + suite.Require().NoError(err, "InsertSyncEntity should succeed") + suite.Assert().False(conflict, "Successful insert should not have conflict") + + updateEntity1 := entity1 + updateEntity1.Version = aws.Int64(2) + updateEntity1.Folder = aws.Bool(true) + updateEntity1.Mtime = aws.Int64(24242424) + conflict, deleted, err := suite.dynamo.UpdateSyncEntity(&updateEntity1, 1) + suite.Require().NoError(err, "UpdateSyncEntity should succeed") + suite.Assert().False(conflict, "Successful update should not have conflict") + suite.Assert().False(deleted, "Non-delete operation should return false") + + // should still succeed with the same version number, + // since the version number should be ignored + updateEntity2 := updateEntity1 + updateEntity2.Mtime = aws.Int64(42424242) + conflict, deleted, err = suite.dynamo.UpdateSyncEntity(&updateEntity2, 1) + suite.Require().NoError(err, "UpdateSyncEntity should not return an error") + suite.Assert().False(conflict, "Successful update should not have conflict") + suite.Assert().False(deleted, "Non-delete operation should return false") + + updateEntity3 := entity1 + updateEntity3.Deleted = aws.Bool(true) + + conflict, deleted, err = suite.dynamo.UpdateSyncEntity(&updateEntity3, 1) + suite.Require().NoError(err, "UpdateSyncEntity should succeed") + suite.Assert().False(conflict, "Successful update should not have conflict") + suite.Assert().True(deleted, "Delete operation should return true") + + syncItems, err := datastoretest.ScanSyncEntities(suite.dynamo) + suite.Require().NoError(err, "ScanSyncEntities should succeed") + suite.Assert().Equal(syncItems, []datastore.SyncEntity{updateEntity3}) +} + func (suite *SyncEntityTestSuite) TestUpdateSyncEntity_ReuseClientTag() { // Insert an item with client tag. entity1 := datastore.SyncEntity{ @@ -438,9 +528,17 @@ func (suite *SyncEntityTestSuite) TestGetUpdatesForType() { entity3.DataType = aws.Int(124) entity3.DataTypeMtime = aws.String("124#12345679") + // non-expired item entity4 := entity2 entity4.ClientID = "client2" entity4.ID = "id4" + entity4.ExpirationTime = aws.Int64(time.Now().Unix() + 300) + + // expired item + entity5 := entity2 + entity5.ClientID = "client2" + entity5.ID = "id5" + entity5.ExpirationTime = aws.Int64(time.Now().Unix() - 300) _, err := suite.dynamo.InsertSyncEntity(&entity1) suite.Require().NoError(err, "InsertSyncEntity should succeed") @@ -450,6 +548,8 @@ func (suite *SyncEntityTestSuite) TestGetUpdatesForType() { suite.Require().NoError(err, "InsertSyncEntity should succeed") _, err = suite.dynamo.InsertSyncEntity(&entity4) suite.Require().NoError(err, "InsertSyncEntity should succeed") + _, err = suite.dynamo.InsertSyncEntity(&entity5) + suite.Require().NoError(err, "InsertSyncEntity should succeed") // Get all updates for type 123 and client1 using token = 0. hasChangesRemaining, syncItems, err := suite.dynamo.GetUpdatesForType(123, 0, true, "client1", 100) @@ -585,6 +685,7 @@ func (suite *SyncEntityTestSuite) TestCreateDBSyncEntity() { DataType: aws.Int(47745), // nigori type ID OriginatorCacheGUID: guid, OriginatorClientItemID: pbEntity.IdString, + ExpirationTime: nil, } dbEntity, err := datastore.CreateDBSyncEntity(&pbEntity, guid, "client1") @@ -609,6 +710,7 @@ func (suite *SyncEntityTestSuite) TestCreateDBSyncEntity() { expectedDBEntity.Mtime = dbEntity.Mtime expectedDBEntity.DataTypeMtime = aws.String("47745#" + strconv.FormatInt(*dbEntity.Mtime, 10)) suite.Assert().Equal(dbEntity, &expectedDBEntity) + suite.Assert().Nil(dbEntity.ExpirationTime) pbEntity.Deleted = nil pbEntity.Folder = nil @@ -616,6 +718,7 @@ func (suite *SyncEntityTestSuite) TestCreateDBSyncEntity() { suite.Require().NoError(err, "CreateDBSyncEntity should succeed") suite.Assert().False(*dbEntity.Deleted, "Default value should be set for Deleted for new entities") suite.Assert().False(*dbEntity.Folder, "Default value should be set for Deleted for new entities") + suite.Assert().Nil(dbEntity.ExpirationTime) // Check the case when Ctime and Mtime are provided by the client. pbEntity.Ctime = aws.Int64(12345678) @@ -624,6 +727,7 @@ func (suite *SyncEntityTestSuite) TestCreateDBSyncEntity() { suite.Require().NoError(err, "CreateDBSyncEntity should succeed") suite.Assert().Equal(*dbEntity.Ctime, *pbEntity.Ctime, "Client's Ctime should be respected") suite.Assert().NotEqual(*dbEntity.Mtime, *pbEntity.Mtime, "Client's Mtime should be replaced") + suite.Assert().Nil(dbEntity.ExpirationTime) // When cacheGUID is nil, ID should be kept and no originator info are filled. dbEntity, err = datastore.CreateDBSyncEntity(&pbEntity, nil, "client1") @@ -631,6 +735,7 @@ func (suite *SyncEntityTestSuite) TestCreateDBSyncEntity() { suite.Assert().Equal(dbEntity.ID, *pbEntity.IdString) suite.Assert().Nil(dbEntity.OriginatorCacheGUID) suite.Assert().Nil(dbEntity.OriginatorClientItemID) + suite.Assert().Nil(dbEntity.ExpirationTime) // Check that when updating from a previous version with guid, ID will not be // replaced. @@ -640,12 +745,25 @@ func (suite *SyncEntityTestSuite) TestCreateDBSyncEntity() { suite.Assert().Equal(dbEntity.ID, *pbEntity.IdString) suite.Assert().Nil(dbEntity.Deleted, "Deleted won't apply its default value for updated entities") suite.Assert().Nil(dbEntity.Folder, "Deleted won't apply its default value for updated entities") + suite.Assert().Nil(dbEntity.ExpirationTime) // Empty unique position should be marshalled to nil without error. pbEntity.UniquePosition = nil dbEntity, err = datastore.CreateDBSyncEntity(&pbEntity, guid, "client1") suite.Require().NoError(err) suite.Assert().Nil(dbEntity.UniquePosition) + suite.Assert().Nil(dbEntity.ExpirationTime) + + // A history entity should have the client tag hash as the ID, + // and an expiration time. + historyEntitySpecific := &sync_pb.EntitySpecifics_History{} + pbEntity.Specifics = &sync_pb.EntitySpecifics{SpecificsVariant: historyEntitySpecific} + dbEntity, err = datastore.CreateDBSyncEntity(&pbEntity, guid, "client1") + suite.Require().NoError(err) + suite.Assert().Equal(dbEntity.ID, "client_tag") + expectedExpirationTime := time.Now().Unix() + datastore.HistoryExpirationIntervalSecs + suite.Assert().Greater(*dbEntity.ExpirationTime+2, expectedExpirationTime) + suite.Assert().Less(*dbEntity.ExpirationTime-2, expectedExpirationTime) // Empty specifics should report marshal error. pbEntity.Specifics = nil diff --git a/dynamo.Dockerfile b/dynamo.Dockerfile index ee2e48f7..dd13eb70 100644 --- a/dynamo.Dockerfile +++ b/dynamo.Dockerfile @@ -19,6 +19,9 @@ RUN mkdir -p ${DB_LOCATION} && \ sleep 15 && \ aws dynamodb create-table --cli-input-json file://table.json \ --endpoint-url ${AWS_ENDPOINT} --region ${AWS_REGION} && \ + aws dynamodb update-time-to-live --table-name client-entity-dev \ + --time-to-live-specification "Enabled=true, AttributeName=ExpirationTime" \ + --endpoint-url http://localhost:8000 && \ kill $DYNAMO_PID FROM amazon/dynamodb-local:2.0.0 diff --git a/go.mod b/go.mod index 0e1a2892..fa82bfe4 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,9 @@ module github.com/brave/go-sync go 1.18 require ( - github.com/aws/aws-sdk-go v1.45.8 - github.com/brave-intl/bat-go/libs v0.0.0-20230911092351-1d5d359ef563 - github.com/getsentry/sentry-go v0.24.0 + github.com/aws/aws-sdk-go v1.45.19 + github.com/brave-intl/bat-go/libs v0.0.0-20230913115141-8b4fe85da72c + github.com/getsentry/sentry-go v0.24.1 github.com/go-chi/chi/v5 v5.0.10 github.com/prometheus/client_golang v1.16.0 github.com/redis/go-redis/v9 v9.1.0 diff --git a/go.sum b/go.sum index bb7e4394..19002a70 100644 --- a/go.sum +++ b/go.sum @@ -4,10 +4,16 @@ github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aws/aws-sdk-go v1.45.8 h1:QbOMBTuRYx11fBwNSAJuztXmQf47deFz+CVYjakqmRo= github.com/aws/aws-sdk-go v1.45.8/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.45.11 h1:8qiSrA12+NRr+2MVpMApi3JxtiFFjDVU1NeWe+80bYg= +github.com/aws/aws-sdk-go v1.45.11/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.45.19 h1:+4yXWhldhCVXWFOQRF99ZTJ92t4DtoHROZIbN7Ujk/U= +github.com/aws/aws-sdk-go v1.45.19/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/brave-intl/bat-go/libs v0.0.0-20230911092351-1d5d359ef563 h1:1G4hpyfq1Rgeb3FO9LeXyACuX/zn6oDIssM0fma5z+A= github.com/brave-intl/bat-go/libs v0.0.0-20230911092351-1d5d359ef563/go.mod h1:sUyKgpr9uxg0SARewNEkNMStvBjOeWuWoLchHgyONGA= +github.com/brave-intl/bat-go/libs v0.0.0-20230913115141-8b4fe85da72c h1:siIB7Odcs3x4CKYY8Nqdbkk+BEH+Js8yP6Kg1SjS3xo= +github.com/brave-intl/bat-go/libs v0.0.0-20230913115141-8b4fe85da72c/go.mod h1:sUyKgpr9uxg0SARewNEkNMStvBjOeWuWoLchHgyONGA= github.com/bsm/ginkgo/v2 v2.9.5 h1:rtVBYPs3+TC5iLUVOis1B9tjLTup7Cj5IfzosKtvTJ0= github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= @@ -21,6 +27,8 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/getsentry/sentry-go v0.24.0 h1:02b7qEmJ56EHGe9KFgjArjU/vG/aywm7Efgu+iPc01Y= github.com/getsentry/sentry-go v0.24.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= +github.com/getsentry/sentry-go v0.24.1 h1:W6/0GyTy8J6ge6lVCc94WB6Gx2ZuLrgopnn9w8Hiwuk= +github.com/getsentry/sentry-go v0.24.1/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec= github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= diff --git a/renovate.json b/renovate.json index 39a2b6e9..fb814dce 100644 --- a/renovate.json +++ b/renovate.json @@ -1,6 +1,6 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": [ - "config:base" + "local>brave/renovate-config" ] }