This is an automated email from the ASF dual-hosted git repository.

lahirujayathilake pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/airavata-custos.git

commit 1d7f16cbfc61ff8f51e1cac0e3931ec6b36aaebc
Author: lahiruj <[email protected]>
AuthorDate: Mon Apr 20 16:00:15 2026 -0400

    Add person soft-delete, email dedup, and GlobalID mapping for AMIE merge 
support
      - Replace hard-delete with soft-delete (is_active flag) on person merge
      - Deduplicate persons by email to avoid creating multiple accounts for 
the same person with different ACCESS Global IDs
      - Add person_global_ids mapping table so a person can be looked up by any 
of their historical Global IDs
      - Rename amie_audit_logs table to amie_audit_log
---
 .../{store/audit_store.go => db/errors.go}         |  31 +-
 .../db/migrations/000001_initial_schema.down.sql   |   3 +-
 .../db/migrations/000001_initial_schema.up.sql     |  17 +-
 allocations/access-amie/main.go                    |  19 +-
 allocations/access-amie/service/account_service.go |  17 +-
 .../access-amie/service/membership_service.go      |   4 +
 allocations/access-amie/service/person_service.go  | 112 +++--
 .../access-amie/service/person_service_test.go     | 117 ++++--
 allocations/access-amie/service/project_service.go |   4 +
 allocations/access-amie/store/audit_store.go       |   2 +-
 allocations/access-amie/worker/processor.go        |  27 +-
 allocations/domain/model/person.go                 |   7 +
 allocations/domain/store/person_store.go           |  46 ++-
 allocations/domain/store/stores.go                 |   9 +
 allocations/go.work.sum                            | 451 +++++++++++++++++++++
 15 files changed, 750 insertions(+), 116 deletions(-)

diff --git a/allocations/access-amie/store/audit_store.go 
b/allocations/access-amie/db/errors.go
similarity index 53%
copy from allocations/access-amie/store/audit_store.go
copy to allocations/access-amie/db/errors.go
index 5a06e15df..aed2591c1 100644
--- a/allocations/access-amie/store/audit_store.go
+++ b/allocations/access-amie/db/errors.go
@@ -15,32 +15,17 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package store
+package db
 
 import (
-       "context"
-       "database/sql"
+       "errors"
 
-       "github.com/apache/airavata-custos/allocations/access-amie/model"
-       "github.com/jmoiron/sqlx"
+       "github.com/go-sql-driver/mysql"
 )
 
-type AuditStore interface {
-       Save(ctx context.Context, tx *sql.Tx, a *model.AuditLog) error
-}
-
-type mariaDBauditStore struct {
-       db *sqlx.DB
-}
-
-func NewAuditStore(db *sqlx.DB) AuditStore {
-       return &mariaDBauditStore{db: db}
-}
-
-func (s *mariaDBauditStore) Save(ctx context.Context, tx *sql.Tx, a 
*model.AuditLog) error {
-       _, err := tx.ExecContext(ctx,
-               `INSERT INTO amie_audit_logs (packet_id, event_id, action, 
entity_type, entity_id, summary, created_at)
-                VALUES (?, ?, ?, ?, ?, ?, ?)`,
-               a.PacketID, a.EventID, a.Action, a.EntityType, a.EntityID, 
a.Summary, a.CreatedAt)
-       return err
+// IsDuplicateKeyError returns true if the error is a MariaDB/MySQL duplicate
+// key violation (error code 1062).
+func IsDuplicateKeyError(err error) bool {
+       var dbErr *mysql.MySQLError
+       return errors.As(err, &dbErr) && dbErr.Number == 1062
 }
diff --git 
a/allocations/access-amie/db/migrations/000001_initial_schema.down.sql 
b/allocations/access-amie/db/migrations/000001_initial_schema.down.sql
index 7821cf204..0affd31bb 100644
--- a/allocations/access-amie/db/migrations/000001_initial_schema.down.sql
+++ b/allocations/access-amie/db/migrations/000001_initial_schema.down.sql
@@ -15,7 +15,7 @@
 -- specific language governing permissions and limitations
 -- under the License.
 
-DROP TABLE IF EXISTS amie_audit_logs;
+DROP TABLE IF EXISTS amie_audit_log;
 DROP TABLE IF EXISTS amie_processing_errors;
 DROP TABLE IF EXISTS amie_processing_events;
 DROP TABLE IF EXISTS amie_packets;
@@ -23,4 +23,5 @@ DROP TABLE IF EXISTS project_memberships;
 DROP TABLE IF EXISTS projects;
 DROP TABLE IF EXISTS cluster_accounts;
 DROP TABLE IF EXISTS person_dns;
+DROP TABLE IF EXISTS person_global_ids;
 DROP TABLE IF EXISTS persons;
diff --git a/allocations/access-amie/db/migrations/000001_initial_schema.up.sql 
b/allocations/access-amie/db/migrations/000001_initial_schema.up.sql
index beacd370d..51870b778 100644
--- a/allocations/access-amie/db/migrations/000001_initial_schema.up.sql
+++ b/allocations/access-amie/db/migrations/000001_initial_schema.up.sql
@@ -28,10 +28,23 @@ CREATE TABLE IF NOT EXISTS persons
     organization     VARCHAR(255) NULL,
     org_code         VARCHAR(255) NULL,
     nsf_status_code  VARCHAR(32)  NULL,
+    is_active        BOOLEAN      NOT NULL DEFAULT TRUE,
     created_at       TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
     updated_at       TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON 
UPDATE CURRENT_TIMESTAMP(6),
     PRIMARY KEY (id),
-    UNIQUE KEY uq_persons_amie_global_id (access_global_id)
+    UNIQUE KEY uq_persons_amie_global_id (access_global_id),
+    KEY idx_persons_active (is_active),
+    KEY idx_persons_email (email)
+) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
+
+CREATE TABLE IF NOT EXISTS person_global_ids
+(
+    id        BIGINT       NOT NULL AUTO_INCREMENT,
+    person_id VARCHAR(255) NOT NULL,
+    global_id VARCHAR(255) NOT NULL,
+    PRIMARY KEY (id),
+    CONSTRAINT fk_global_ids_person FOREIGN KEY (person_id) REFERENCES persons 
(id) ON DELETE CASCADE,
+    UNIQUE KEY uq_person_global_id (global_id)
 ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
 
 CREATE TABLE IF NOT EXISTS person_dns
@@ -142,7 +155,7 @@ CREATE TABLE IF NOT EXISTS amie_processing_errors
     KEY idx_errors_amie_occurred_at (occurred_at)
 ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
 
-CREATE TABLE IF NOT EXISTS amie_audit_logs
+CREATE TABLE IF NOT EXISTS amie_audit_log
 (
     id          BIGINT       NOT NULL AUTO_INCREMENT,
     packet_id   VARCHAR(255) NOT NULL,
diff --git a/allocations/access-amie/main.go b/allocations/access-amie/main.go
index 77e78b424..74ddd4d42 100644
--- a/allocations/access-amie/main.go
+++ b/allocations/access-amie/main.go
@@ -22,6 +22,7 @@ import (
        "log/slog"
        "os"
        "os/signal"
+       "sync"
        "syscall"
 
        "github.com/apache/airavata-custos/allocations/access-amie/amieclient"
@@ -61,6 +62,7 @@ func main() {
 
        personStore := domainstore.NewPersonStore(database)
        personDNStore := domainstore.NewPersonDNStore(database)
+       personGlobalIDStore := domainstore.NewPersonGlobalIDStore(database)
        accountStore := domainstore.NewClusterAccountStore(database)
        projectStore := domainstore.NewProjectStore(database)
        membershipStore := domainstore.NewMembershipStore(database)
@@ -69,7 +71,7 @@ func main() {
        errorStore := store.NewProcessingErrorStore(database)
        auditStore := store.NewAuditStore(database)
 
-       personSvc := service.NewPersonService(personStore, personDNStore, 
accountStore)
+       personSvc := service.NewPersonService(personStore, personDNStore, 
accountStore, personGlobalIDStore)
        accountSvc := service.NewUserAccountService(accountStore)
        projectSvc := service.NewProjectService(projectStore)
        membershipSvc := service.NewProjectMembershipService(membershipStore, 
projectStore, accountStore)
@@ -108,13 +110,22 @@ func main() {
        ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, 
syscall.SIGTERM)
        defer cancel()
 
-       go poller.Run(ctx)
-       go processor.Run(ctx)
+       var wg sync.WaitGroup
+       wg.Add(2)
+       go func() {
+               defer wg.Done()
+               poller.Run(ctx)
+       }()
+       go func() {
+               defer wg.Done()
+               processor.Run(ctx)
+       }()
 
        slog.Info("access-amie service started successfully")
        <-ctx.Done()
 
-       slog.Info("shutting down...")
+       slog.Info("shutting down, waiting for workers to finish...")
+       wg.Wait()
        if err := srv.Shutdown(context.Background()); err != nil {
                slog.Error("HTTP server shutdown error", "error", err)
        }
diff --git a/allocations/access-amie/service/account_service.go 
b/allocations/access-amie/service/account_service.go
index 632fb224c..473e104c2 100644
--- a/allocations/access-amie/service/account_service.go
+++ b/allocations/access-amie/service/account_service.go
@@ -23,7 +23,9 @@ import (
        "fmt"
        "log/slog"
        "strings"
+       "time"
 
+       "github.com/apache/airavata-custos/allocations/access-amie/db"
        "github.com/apache/airavata-custos/allocations/domain/model"
        "github.com/google/uuid"
 )
@@ -59,16 +61,19 @@ func (s *UserAccountService) ProvisionClusterAccount(ctx 
context.Context, tx *sq
                return nil, fmt.Errorf("account_service: ensuring unique 
username for person %s: %w", person.ID, err)
        }
 
+       now := time.Now().UTC()
        acct := &model.ClusterAccount{
-               ID:       uuid.NewString(),
-               PersonID: person.ID,
-               Username: uniqueUsername,
+               ID:        uuid.NewString(),
+               PersonID:  person.ID,
+               Username:  uniqueUsername,
+               CreatedAt: now,
+               UpdatedAt: now,
        }
 
        if err := s.accounts.Save(ctx, tx, acct); err != nil {
-               // Handle MySQL duplicate key race condition: another 
transaction
-               // may have inserted a record between our check and insert.
-               if strings.Contains(err.Error(), "Duplicate entry") {
+               // Handle MariaDB duplicate key race condition:
+               // another transaction may have inserted a record between our 
check and insert.
+               if db.IsDuplicateKeyError(err) {
                        retryExisting, retryErr := s.accounts.FindByPerson(ctx, 
person.ID)
                        if retryErr != nil {
                                return nil, fmt.Errorf("account_service: retry 
finding accounts for person %s: %w", person.ID, retryErr)
diff --git a/allocations/access-amie/service/membership_service.go 
b/allocations/access-amie/service/membership_service.go
index 119107b53..f2233efcb 100644
--- a/allocations/access-amie/service/membership_service.go
+++ b/allocations/access-amie/service/membership_service.go
@@ -22,6 +22,7 @@ import (
        "database/sql"
        "fmt"
        "log/slog"
+       "time"
 
        "github.com/apache/airavata-custos/allocations/domain/model"
        "github.com/google/uuid"
@@ -81,12 +82,15 @@ func (s *ProjectMembershipService) CreateMembership(ctx 
context.Context, tx *sql
                return existing, nil
        }
 
+       now := time.Now().UTC()
        m := &model.ProjectMembership{
                ID:               uuid.NewString(),
                ProjectID:        projectID,
                ClusterAccountID: clusterAccountID,
                Role:             &role,
                IsActive:         true,
+               CreatedAt:        now,
+               UpdatedAt:        now,
        }
 
        if err := s.memberships.Save(ctx, tx, m); err != nil {
diff --git a/allocations/access-amie/service/person_service.go 
b/allocations/access-amie/service/person_service.go
index ea9391b9d..131a4aeaf 100644
--- a/allocations/access-amie/service/person_service.go
+++ b/allocations/access-amie/service/person_service.go
@@ -22,6 +22,7 @@ import (
        "database/sql"
        "fmt"
        "log/slog"
+       "time"
 
        "github.com/apache/airavata-custos/allocations/domain/model"
        "github.com/google/uuid"
@@ -30,7 +31,10 @@ import (
 type personStore interface {
        FindByID(ctx context.Context, id string) (*model.Person, error)
        FindByAccessGlobalID(ctx context.Context, globalID string) 
(*model.Person, error)
+       FindActiveByEmail(ctx context.Context, email string) (*model.Person, 
error)
        Save(ctx context.Context, tx *sql.Tx, p *model.Person) error
+       Update(ctx context.Context, tx *sql.Tx, p *model.Person) error
+       Deactivate(ctx context.Context, tx *sql.Tx, id string) error
        Delete(ctx context.Context, tx *sql.Tx, id string) error
 }
 
@@ -47,29 +51,39 @@ type personAccountStore interface {
        UpdatePersonID(ctx context.Context, tx *sql.Tx, accountID, newPersonID 
string) error
 }
 
+type personGlobalIDStore interface {
+       FindPersonByGlobalID(ctx context.Context, globalID string) 
(*model.Person, error)
+       Save(ctx context.Context, tx *sql.Tx, g *model.PersonGlobalID) error
+       UpdatePersonID(ctx context.Context, tx *sql.Tx, oldPersonID, 
newPersonID string) error
+}
+
 type PersonService struct {
-       persons  personStore
-       dns      personDNStore
-       accounts personAccountStore
+       persons   personStore
+       dns       personDNStore
+       accounts  personAccountStore
+       globalIDs personGlobalIDStore
 }
 
-func NewPersonService(persons personStore, dns personDNStore, accounts 
personAccountStore) *PersonService {
+func NewPersonService(persons personStore, dns personDNStore, accounts 
personAccountStore, globalIDs personGlobalIDStore) *PersonService {
        return &PersonService{
-               persons:  persons,
-               dns:      dns,
-               accounts: accounts,
+               persons:   persons,
+               dns:       dns,
+               accounts:  accounts,
+               globalIDs: globalIDs,
        }
 }
 
-// FindOrCreateFromPacket looks up a person by their ACCESS Global ID or
-// creates a new person record from the supplied AMIE packet body.
+// FindOrCreateFromPacket looks up a person by their ACCESS Global ID (via the
+// mapping table), then by email. Creates a new person only if neither lookup
+// finds an existing active person. This deduplicates persons who share the 
same
+// email but arrive with different ACCESS Global IDs.
 func (s *PersonService) FindOrCreateFromPacket(ctx context.Context, tx 
*sql.Tx, body map[string]any) (*model.Person, error) {
        globalID, _ := body["UserGlobalID"].(string)
        if globalID == "" {
                return nil, fmt.Errorf("person_service: UserGlobalID is 
required")
        }
 
-       existing, err := s.persons.FindByAccessGlobalID(ctx, globalID)
+       existing, err := s.globalIDs.FindPersonByGlobalID(ctx, globalID)
        if err != nil {
                return nil, fmt.Errorf("person_service: finding person by 
global ID %s: %w", globalID, err)
        }
@@ -77,10 +91,31 @@ func (s *PersonService) FindOrCreateFromPacket(ctx 
context.Context, tx *sql.Tx,
                return existing, nil
        }
 
+       email, _ := body["UserEmail"].(string)
+       if email != "" {
+               byEmail, err := s.persons.FindActiveByEmail(ctx, email)
+               if err != nil {
+                       return nil, fmt.Errorf("person_service: finding person 
by email %s: %w", email, err)
+               }
+               if byEmail != nil {
+                       slog.InfoContext(ctx, "deduplicating person by email", 
"person_id", byEmail.ID, "email", email, "new_global_id", globalID)
+
+                       byEmail.AccessGlobalID = globalID
+                       if err := s.persons.Update(ctx, tx, byEmail); err != 
nil {
+                               return nil, fmt.Errorf("person_service: 
updating person %s with new global ID: %w", byEmail.ID, err)
+                       }
+                       g := &model.PersonGlobalID{PersonID: byEmail.ID, 
GlobalID: globalID}
+                       if err := s.globalIDs.Save(ctx, tx, g); err != nil {
+                               return nil, fmt.Errorf("person_service: saving 
global ID mapping for person %s: %w", byEmail.ID, err)
+                       }
+                       return byEmail, nil
+               }
+       }
+
        firstName, _ := body["UserFirstName"].(string)
        lastName, _ := body["UserLastName"].(string)
-       email, _ := body["UserEmail"].(string)
 
+       now := time.Now().UTC()
        p := &model.Person{
                ID:             uuid.NewString(),
                AccessGlobalID: globalID,
@@ -90,15 +125,22 @@ func (s *PersonService) FindOrCreateFromPacket(ctx 
context.Context, tx *sql.Tx,
                Organization:   optionalString(body, "UserOrganization"),
                OrgCode:        optionalString(body, "UserOrgCode"),
                NsfStatusCode:  optionalString(body, "NsfStatusCode"),
+               IsActive:       true,
+               CreatedAt:      now,
+               UpdatedAt:      now,
        }
 
        if err := s.persons.Save(ctx, tx, p); err != nil {
                return nil, fmt.Errorf("person_service: saving new person %s: 
%w", p.ID, err)
        }
 
+       g := &model.PersonGlobalID{PersonID: p.ID, GlobalID: globalID}
+       if err := s.globalIDs.Save(ctx, tx, g); err != nil {
+               return nil, fmt.Errorf("person_service: saving global ID 
mapping for new person %s: %w", p.ID, err)
+       }
+
        slog.DebugContext(ctx, "created person from packet", "person_id", p.ID, 
"global_id", globalID)
 
-       // Persist DN list if present.
        if dnList, ok := body["UserDnList"].([]any); ok {
                for _, raw := range dnList {
                        dn, _ := raw.(string)
@@ -131,7 +173,6 @@ func (s *PersonService) ReplaceFromModifyPacket(ctx 
context.Context, tx *sql.Tx,
                return fmt.Errorf("person_service: person %s not found", 
personID)
        }
 
-       // Update only fields present in the body.
        if v, ok := body["UserFirstName"]; ok {
                p.FirstName, _ = v.(string)
        }
@@ -151,7 +192,6 @@ func (s *PersonService) ReplaceFromModifyPacket(ctx 
context.Context, tx *sql.Tx,
                p.NsfStatusCode = optionalString(body, "NsfStatusCode")
        }
 
-       // Handle DN list updates.
        if rawDNs, ok := body["UserDnList"]; ok {
                dnList, isList := rawDNs.([]any)
                if isList && len(dnList) > 0 {
@@ -184,8 +224,8 @@ func (s *PersonService) ReplaceFromModifyPacket(ctx 
context.Context, tx *sql.Tx,
                }
        }
 
-       if err := s.persons.Save(ctx, tx, p); err != nil {
-               return fmt.Errorf("person_service: saving updated person %s: 
%w", personID, err)
+       if err := s.persons.Update(ctx, tx, p); err != nil {
+               return fmt.Errorf("person_service: updating person %s: %w", 
personID, err)
        }
 
        slog.DebugContext(ctx, "updated person from modify packet", 
"person_id", personID)
@@ -208,8 +248,10 @@ func (s *PersonService) DeleteFromModifyPacket(ctx 
context.Context, tx *sql.Tx,
        return nil
 }
 
-// MergePersons transfers all accounts and DNs from the retiring person to the
-// surviving person, then deletes the retiring person.
+// MergePersons transfers all accounts, DNs, and GlobalID mappings from the
+// retiring person to the surviving person, then deactivates the retiring 
person.
+// If the retiring person is not found or already inactive (e.g., email dedup
+// already consolidated them), the merge is treated as a no-op.
 func (s *PersonService) MergePersons(ctx context.Context, tx *sql.Tx, 
survivingID, retiringID string) error {
        surviving, err := s.persons.FindByID(ctx, survivingID)
        if err != nil {
@@ -224,10 +266,14 @@ func (s *PersonService) MergePersons(ctx context.Context, 
tx *sql.Tx, survivingI
                return fmt.Errorf("person_service: finding retiring person %s: 
%w", retiringID, err)
        }
        if retiring == nil {
-               return fmt.Errorf("person_service: retiring person %s not 
found", retiringID)
+               slog.WarnContext(ctx, "retiring person not found, merge is a 
no-op (may have been deduplicated)", "retiring_id", retiringID, "surviving_id", 
survivingID)
+               return nil
+       }
+       if !retiring.IsActive {
+               slog.WarnContext(ctx, "retiring person already inactive, merge 
is a no-op", "retiring_id", retiringID, "surviving_id", survivingID)
+               return nil
        }
 
-       // Move cluster accounts from the retiring person to the surviving 
person.
        retiringAccounts, err := s.accounts.FindByPerson(ctx, retiringID)
        if err != nil {
                return fmt.Errorf("person_service: finding accounts for 
retiring person %s: %w", retiringID, err)
@@ -257,18 +303,34 @@ func (s *PersonService) MergePersons(ctx context.Context, 
tx *sql.Tx, survivingI
                }
        }
 
-       // Delete the retiring person; cascade rules handle related records.
-       if err := s.persons.Delete(ctx, tx, retiringID); err != nil {
-               return fmt.Errorf("person_service: deleting retiring person %s: 
%w", retiringID, err)
+       if err := s.globalIDs.UpdatePersonID(ctx, tx, retiringID, survivingID); 
err != nil {
+               return fmt.Errorf("person_service: reassigning global IDs from 
%s to %s: %w", retiringID, survivingID, err)
+       }
+
+       if err := s.persons.Deactivate(ctx, tx, retiringID); err != nil {
+               return fmt.Errorf("person_service: deactivating retiring person 
%s: %w", retiringID, err)
        }
 
-       slog.DebugContext(ctx, "merged persons", "surviving_id", survivingID, 
"retiring_id", retiringID)
+       slog.InfoContext(ctx, "merged persons", "surviving_id", survivingID, 
"retiring_id", retiringID)
        return nil
 }
 
 // PersistDNsForPerson saves any distinguished names that the person does not
-// already have.
+// already have. Skips gracefully if person is not found or inactive.
 func (s *PersonService) PersistDNsForPerson(ctx context.Context, tx *sql.Tx, 
personID string, dnList []string) error {
+       p, err := s.persons.FindByID(ctx, personID)
+       if err != nil {
+               return fmt.Errorf("person_service: finding person %s: %w", 
personID, err)
+       }
+       if p == nil {
+               slog.WarnContext(ctx, "skipping DN persistence for unknown 
person (may have been merged/deleted)", "person_id", personID)
+               return nil
+       }
+       if !p.IsActive {
+               slog.WarnContext(ctx, "skipping DN persistence for inactive 
person (merged)", "person_id", personID)
+               return nil
+       }
+
        for _, dn := range dnList {
                exists, err := s.dns.ExistsByPersonAndDN(ctx, personID, dn)
                if err != nil {
diff --git a/allocations/access-amie/service/person_service_test.go 
b/allocations/access-amie/service/person_service_test.go
index 621682579..7aeee129e 100644
--- a/allocations/access-amie/service/person_service_test.go
+++ b/allocations/access-amie/service/person_service_test.go
@@ -58,6 +58,24 @@ func (m *mockPersonStore) Save(ctx context.Context, tx 
*sql.Tx, p *model.Person)
        return args.Error(0)
 }
 
+func (m *mockPersonStore) Update(ctx context.Context, tx *sql.Tx, p 
*model.Person) error {
+       args := m.Called(ctx, tx, p)
+       return args.Error(0)
+}
+
+func (m *mockPersonStore) FindActiveByEmail(ctx context.Context, email string) 
(*model.Person, error) {
+       args := m.Called(ctx, email)
+       if args.Get(0) == nil {
+               return nil, args.Error(1)
+       }
+       return args.Get(0).(*model.Person), args.Error(1)
+}
+
+func (m *mockPersonStore) Deactivate(ctx context.Context, tx *sql.Tx, id 
string) error {
+       args := m.Called(ctx, tx, id)
+       return args.Error(0)
+}
+
 func (m *mockPersonStore) Delete(ctx context.Context, tx *sql.Tx, id string) 
error {
        args := m.Called(ctx, tx, id)
        return args.Error(0)
@@ -112,6 +130,28 @@ func (m *mockPersonAccountStore) UpdatePersonID(ctx 
context.Context, tx *sql.Tx,
        return args.Error(0)
 }
 
+type mockPersonGlobalIDStore struct {
+       mock.Mock
+}
+
+func (m *mockPersonGlobalIDStore) FindPersonByGlobalID(ctx context.Context, 
globalID string) (*model.Person, error) {
+       args := m.Called(ctx, globalID)
+       if args.Get(0) == nil {
+               return nil, args.Error(1)
+       }
+       return args.Get(0).(*model.Person), args.Error(1)
+}
+
+func (m *mockPersonGlobalIDStore) Save(ctx context.Context, tx *sql.Tx, g 
*model.PersonGlobalID) error {
+       args := m.Called(ctx, tx, g)
+       return args.Error(0)
+}
+
+func (m *mockPersonGlobalIDStore) UpdatePersonID(ctx context.Context, tx 
*sql.Tx, oldPersonID, newPersonID string) error {
+       args := m.Called(ctx, tx, oldPersonID, newPersonID)
+       return args.Error(0)
+}
+
 // ---------------------------------------------------------------------------
 // FindOrCreateFromPacket tests
 // ---------------------------------------------------------------------------
@@ -121,17 +161,18 @@ func TestFindOrCreateFromPacket_FindExistingByGlobalID(t 
*testing.T) {
        persons := new(mockPersonStore)
        dns := new(mockPersonDNStore)
        accounts := new(mockPersonAccountStore)
-       svc := NewPersonService(persons, dns, accounts)
+       globalIDs := new(mockPersonGlobalIDStore)
+       svc := NewPersonService(persons, dns, accounts, globalIDs)
 
        existing := &model.Person{ID: "p1", AccessGlobalID: "global-123"}
-       persons.On("FindByAccessGlobalID", ctx, "global-123").Return(existing, 
nil)
+       globalIDs.On("FindPersonByGlobalID", ctx, 
"global-123").Return(existing, nil)
 
        body := map[string]any{"UserGlobalID": "global-123"}
        got, err := svc.FindOrCreateFromPacket(ctx, nil, body)
 
        require.NoError(t, err)
        assert.Equal(t, existing, got)
-       persons.AssertExpectations(t)
+       globalIDs.AssertExpectations(t)
 }
 
 func TestFindOrCreateFromPacket_CreateNewWithAllFields(t *testing.T) {
@@ -139,10 +180,13 @@ func TestFindOrCreateFromPacket_CreateNewWithAllFields(t 
*testing.T) {
        persons := new(mockPersonStore)
        dns := new(mockPersonDNStore)
        accounts := new(mockPersonAccountStore)
-       svc := NewPersonService(persons, dns, accounts)
+       globalIDs := new(mockPersonGlobalIDStore)
+       svc := NewPersonService(persons, dns, accounts, globalIDs)
 
-       persons.On("FindByAccessGlobalID", ctx, "global-456").Return(nil, nil)
+       globalIDs.On("FindPersonByGlobalID", ctx, "global-456").Return(nil, nil)
+       persons.On("FindActiveByEmail", ctx, "[email protected]").Return(nil, 
nil)
        persons.On("Save", ctx, mock.Anything, 
mock.AnythingOfType("*model.Person")).Return(nil)
+       globalIDs.On("Save", ctx, mock.Anything, 
mock.AnythingOfType("*model.PersonGlobalID")).Return(nil)
 
        body := map[string]any{
                "UserGlobalID":     "global-456",
@@ -164,6 +208,7 @@ func TestFindOrCreateFromPacket_CreateNewWithAllFields(t 
*testing.T) {
        require.NotNil(t, got.Organization)
        assert.Equal(t, "Test Org", *got.Organization)
        persons.AssertExpectations(t)
+       globalIDs.AssertExpectations(t)
 }
 
 func TestFindOrCreateFromPacket_CreateWithDNList(t *testing.T) {
@@ -171,10 +216,13 @@ func TestFindOrCreateFromPacket_CreateWithDNList(t 
*testing.T) {
        persons := new(mockPersonStore)
        dns := new(mockPersonDNStore)
        accounts := new(mockPersonAccountStore)
-       svc := NewPersonService(persons, dns, accounts)
+       globalIDs := new(mockPersonGlobalIDStore)
+       svc := NewPersonService(persons, dns, accounts, globalIDs)
 
-       persons.On("FindByAccessGlobalID", ctx, "global-789").Return(nil, nil)
+       globalIDs.On("FindPersonByGlobalID", ctx, "global-789").Return(nil, nil)
+       persons.On("FindActiveByEmail", ctx, "[email protected]").Return(nil, 
nil)
        persons.On("Save", ctx, mock.Anything, 
mock.AnythingOfType("*model.Person")).Return(nil)
+       globalIDs.On("Save", ctx, mock.Anything, 
mock.AnythingOfType("*model.PersonGlobalID")).Return(nil)
        dns.On("Save", ctx, mock.Anything, 
mock.AnythingOfType("*model.PersonDN")).Return(nil).Times(2)
 
        body := map[string]any{
@@ -190,11 +238,12 @@ func TestFindOrCreateFromPacket_CreateWithDNList(t 
*testing.T) {
        require.NotNil(t, got)
        persons.AssertExpectations(t)
        dns.AssertExpectations(t)
+       globalIDs.AssertExpectations(t)
 }
 
 func TestFindOrCreateFromPacket_ErrorOnMissingUserGlobalID(t *testing.T) {
        ctx := context.Background()
-       svc := NewPersonService(new(mockPersonStore), new(mockPersonDNStore), 
new(mockPersonAccountStore))
+       svc := NewPersonService(new(mockPersonStore), new(mockPersonDNStore), 
new(mockPersonAccountStore), new(mockPersonGlobalIDStore))
 
        body := map[string]any{"UserFirstName": "No", "UserLastName": "ID"}
        _, err := svc.FindOrCreateFromPacket(ctx, nil, body)
@@ -212,11 +261,11 @@ func TestReplaceFromModifyPacket_UpdateAllFields(t 
*testing.T) {
        persons := new(mockPersonStore)
        dns := new(mockPersonDNStore)
        accounts := new(mockPersonAccountStore)
-       svc := NewPersonService(persons, dns, accounts)
+       svc := NewPersonService(persons, dns, accounts, 
new(mockPersonGlobalIDStore))
 
        p := &model.Person{ID: "p1", FirstName: "Old", LastName: "Name", Email: 
"[email protected]"}
        persons.On("FindByID", ctx, "p1").Return(p, nil)
-       persons.On("Save", ctx, mock.Anything, p).Return(nil)
+       persons.On("Update", ctx, mock.Anything, p).Return(nil)
 
        body := map[string]any{
                "PersonID":      "p1",
@@ -238,11 +287,11 @@ func TestReplaceFromModifyPacket_PartialUpdate(t 
*testing.T) {
        persons := new(mockPersonStore)
        dns := new(mockPersonDNStore)
        accounts := new(mockPersonAccountStore)
-       svc := NewPersonService(persons, dns, accounts)
+       svc := NewPersonService(persons, dns, accounts, 
new(mockPersonGlobalIDStore))
 
        p := &model.Person{ID: "p1", FirstName: "Keep", LastName: "This", 
Email: "[email protected]"}
        persons.On("FindByID", ctx, "p1").Return(p, nil)
-       persons.On("Save", ctx, mock.Anything, p).Return(nil)
+       persons.On("Update", ctx, mock.Anything, p).Return(nil)
 
        body := map[string]any{
                "PersonID":      "p1",
@@ -261,12 +310,12 @@ func TestReplaceFromModifyPacket_PreserveOrgWhenAbsent(t 
*testing.T) {
        persons := new(mockPersonStore)
        dns := new(mockPersonDNStore)
        accounts := new(mockPersonAccountStore)
-       svc := NewPersonService(persons, dns, accounts)
+       svc := NewPersonService(persons, dns, accounts, 
new(mockPersonGlobalIDStore))
 
        org := "Original Org"
        p := &model.Person{ID: "p1", FirstName: "F", Organization: &org}
        persons.On("FindByID", ctx, "p1").Return(p, nil)
-       persons.On("Save", ctx, mock.Anything, p).Return(nil)
+       persons.On("Update", ctx, mock.Anything, p).Return(nil)
 
        // No UserOrganization key in body - org should be preserved
        body := map[string]any{
@@ -285,12 +334,12 @@ func TestReplaceFromModifyPacket_ClearDNsWhenEmpty(t 
*testing.T) {
        persons := new(mockPersonStore)
        dns := new(mockPersonDNStore)
        accounts := new(mockPersonAccountStore)
-       svc := NewPersonService(persons, dns, accounts)
+       svc := NewPersonService(persons, dns, accounts, 
new(mockPersonGlobalIDStore))
 
        p := &model.Person{ID: "p1"}
        persons.On("FindByID", ctx, "p1").Return(p, nil)
        dns.On("DeleteByPersonID", ctx, mock.Anything, "p1").Return(nil)
-       persons.On("Save", ctx, mock.Anything, p).Return(nil)
+       persons.On("Update", ctx, mock.Anything, p).Return(nil)
 
        body := map[string]any{
                "PersonID":   "p1",
@@ -307,14 +356,14 @@ func TestReplaceFromModifyPacket_UpdateDNList(t 
*testing.T) {
        persons := new(mockPersonStore)
        dns := new(mockPersonDNStore)
        accounts := new(mockPersonAccountStore)
-       svc := NewPersonService(persons, dns, accounts)
+       svc := NewPersonService(persons, dns, accounts, 
new(mockPersonGlobalIDStore))
 
        p := &model.Person{ID: "p1"}
        persons.On("FindByID", ctx, "p1").Return(p, nil)
        dns.On("DeleteByPersonIDNotIn", ctx, mock.Anything, "p1", 
[]string{"/CN=new"}).Return(nil)
        dns.On("ExistsByPersonAndDN", ctx, "p1", "/CN=new").Return(false, nil)
        dns.On("Save", ctx, mock.Anything, 
mock.AnythingOfType("*model.PersonDN")).Return(nil)
-       persons.On("Save", ctx, mock.Anything, p).Return(nil)
+       persons.On("Update", ctx, mock.Anything, p).Return(nil)
 
        body := map[string]any{
                "PersonID":   "p1",
@@ -329,7 +378,7 @@ func TestReplaceFromModifyPacket_UpdateDNList(t *testing.T) 
{
 
 func TestReplaceFromModifyPacket_ErrorOnMissingPersonID(t *testing.T) {
        ctx := context.Background()
-       svc := NewPersonService(new(mockPersonStore), new(mockPersonDNStore), 
new(mockPersonAccountStore))
+       svc := NewPersonService(new(mockPersonStore), new(mockPersonDNStore), 
new(mockPersonAccountStore), new(mockPersonGlobalIDStore))
 
        body := map[string]any{"UserFirstName": "No", "UserLastName": "ID"}
        err := svc.ReplaceFromModifyPacket(ctx, nil, body)
@@ -341,7 +390,7 @@ func TestReplaceFromModifyPacket_ErrorOnMissingPersonID(t 
*testing.T) {
 func TestReplaceFromModifyPacket_ErrorOnUnknownPersonID(t *testing.T) {
        ctx := context.Background()
        persons := new(mockPersonStore)
-       svc := NewPersonService(persons, new(mockPersonDNStore), 
new(mockPersonAccountStore))
+       svc := NewPersonService(persons, new(mockPersonDNStore), 
new(mockPersonAccountStore), new(mockPersonGlobalIDStore))
 
        persons.On("FindByID", ctx, "unknown").Return(nil, nil)
 
@@ -362,8 +411,9 @@ func TestPersistDNsForPerson_PersistNewDN(t *testing.T) {
        persons := new(mockPersonStore)
        dns := new(mockPersonDNStore)
        accounts := new(mockPersonAccountStore)
-       svc := NewPersonService(persons, dns, accounts)
+       svc := NewPersonService(persons, dns, accounts, 
new(mockPersonGlobalIDStore))
 
+       persons.On("FindByID", ctx, "p1").Return(&model.Person{ID: "p1", 
IsActive: true}, nil)
        dns.On("ExistsByPersonAndDN", ctx, "p1", "/CN=new").Return(false, nil)
        dns.On("Save", ctx, mock.Anything, 
mock.AnythingOfType("*model.PersonDN")).Return(nil)
 
@@ -378,8 +428,9 @@ func TestPersistDNsForPerson_SkipExistingDN(t *testing.T) {
        persons := new(mockPersonStore)
        dns := new(mockPersonDNStore)
        accounts := new(mockPersonAccountStore)
-       svc := NewPersonService(persons, dns, accounts)
+       svc := NewPersonService(persons, dns, accounts, 
new(mockPersonGlobalIDStore))
 
+       persons.On("FindByID", ctx, "p1").Return(&model.Person{ID: "p1", 
IsActive: true}, nil)
        dns.On("ExistsByPersonAndDN", ctx, "p1", "/CN=existing").Return(true, 
nil)
        // Save should NOT be called for existing DNs
 
@@ -399,10 +450,11 @@ func TestMergePersons_MoveAccountsAndDNs(t *testing.T) {
        persons := new(mockPersonStore)
        dns := new(mockPersonDNStore)
        accounts := new(mockPersonAccountStore)
-       svc := NewPersonService(persons, dns, accounts)
+       globalIDs := new(mockPersonGlobalIDStore)
+       svc := NewPersonService(persons, dns, accounts, globalIDs)
 
        surviving := &model.Person{ID: "survivor"}
-       retiring := &model.Person{ID: "retiring"}
+       retiring := &model.Person{ID: "retiring", IsActive: true}
 
        persons.On("FindByID", ctx, "survivor").Return(surviving, nil)
        persons.On("FindByID", ctx, "retiring").Return(retiring, nil)
@@ -411,7 +463,8 @@ func TestMergePersons_MoveAccountsAndDNs(t *testing.T) {
        dns.On("FindByPersonID", ctx, 
"retiring").Return([]model.PersonDN{{PersonID: "retiring", DN: 
"/CN=retiring"}}, nil)
        dns.On("ExistsByPersonAndDN", ctx, "survivor", 
"/CN=retiring").Return(false, nil)
        dns.On("Save", ctx, mock.Anything, 
mock.AnythingOfType("*model.PersonDN")).Return(nil)
-       persons.On("Delete", ctx, mock.Anything, "retiring").Return(nil)
+       globalIDs.On("UpdatePersonID", ctx, mock.Anything, "retiring", 
"survivor").Return(nil)
+       persons.On("Deactivate", ctx, mock.Anything, "retiring").Return(nil)
 
        err := svc.MergePersons(ctx, nil, "survivor", "retiring")
 
@@ -419,12 +472,13 @@ func TestMergePersons_MoveAccountsAndDNs(t *testing.T) {
        persons.AssertExpectations(t)
        accounts.AssertExpectations(t)
        dns.AssertExpectations(t)
+       globalIDs.AssertExpectations(t)
 }
 
 func TestMergePersons_ErrorOnUnknownSurvivingPerson(t *testing.T) {
        ctx := context.Background()
        persons := new(mockPersonStore)
-       svc := NewPersonService(persons, new(mockPersonDNStore), 
new(mockPersonAccountStore))
+       svc := NewPersonService(persons, new(mockPersonDNStore), 
new(mockPersonAccountStore), new(mockPersonGlobalIDStore))
 
        persons.On("FindByID", ctx, "missing").Return(nil, nil)
 
@@ -438,7 +492,7 @@ func TestMergePersons_ErrorOnUnknownSurvivingPerson(t 
*testing.T) {
 func TestMergePersons_ErrorOnUnknownRetiringPerson(t *testing.T) {
        ctx := context.Background()
        persons := new(mockPersonStore)
-       svc := NewPersonService(persons, new(mockPersonDNStore), 
new(mockPersonAccountStore))
+       svc := NewPersonService(persons, new(mockPersonDNStore), 
new(mockPersonAccountStore), new(mockPersonGlobalIDStore))
 
        surviving := &model.Person{ID: "survivor"}
        persons.On("FindByID", ctx, "survivor").Return(surviving, nil)
@@ -446,8 +500,7 @@ func TestMergePersons_ErrorOnUnknownRetiringPerson(t 
*testing.T) {
 
        err := svc.MergePersons(ctx, nil, "survivor", "missing-retiring")
 
-       require.Error(t, err)
-       assert.Contains(t, err.Error(), "retiring person")
+       require.NoError(t, err)
        persons.AssertExpectations(t)
 }
 
@@ -458,7 +511,7 @@ func TestMergePersons_ErrorOnUnknownRetiringPerson(t 
*testing.T) {
 func TestDeleteFromModifyPacket_DeleteByID(t *testing.T) {
        ctx := context.Background()
        persons := new(mockPersonStore)
-       svc := NewPersonService(persons, new(mockPersonDNStore), 
new(mockPersonAccountStore))
+       svc := NewPersonService(persons, new(mockPersonDNStore), 
new(mockPersonAccountStore), new(mockPersonGlobalIDStore))
 
        persons.On("Delete", ctx, mock.Anything, "p1").Return(nil)
 
@@ -471,7 +524,7 @@ func TestDeleteFromModifyPacket_DeleteByID(t *testing.T) {
 
 func TestDeleteFromModifyPacket_ErrorOnMissingPersonID(t *testing.T) {
        ctx := context.Background()
-       svc := NewPersonService(new(mockPersonStore), new(mockPersonDNStore), 
new(mockPersonAccountStore))
+       svc := NewPersonService(new(mockPersonStore), new(mockPersonDNStore), 
new(mockPersonAccountStore), new(mockPersonGlobalIDStore))
 
        body := map[string]any{}
        err := svc.DeleteFromModifyPacket(ctx, nil, body)
@@ -483,7 +536,7 @@ func TestDeleteFromModifyPacket_ErrorOnMissingPersonID(t 
*testing.T) {
 func TestDeleteFromModifyPacket_PropagatesStoreError(t *testing.T) {
        ctx := context.Background()
        persons := new(mockPersonStore)
-       svc := NewPersonService(persons, new(mockPersonDNStore), 
new(mockPersonAccountStore))
+       svc := NewPersonService(persons, new(mockPersonDNStore), 
new(mockPersonAccountStore), new(mockPersonGlobalIDStore))
 
        persons.On("Delete", ctx, mock.Anything, "p1").Return(errors.New("db 
error"))
 
diff --git a/allocations/access-amie/service/project_service.go 
b/allocations/access-amie/service/project_service.go
index f21012aab..3d2ffd60a 100644
--- a/allocations/access-amie/service/project_service.go
+++ b/allocations/access-amie/service/project_service.go
@@ -22,6 +22,7 @@ import (
        "database/sql"
        "fmt"
        "log/slog"
+       "time"
 
        "github.com/apache/airavata-custos/allocations/domain/model"
 )
@@ -51,10 +52,13 @@ func (s *ProjectService) CreateOrFindProject(ctx 
context.Context, tx *sql.Tx, pr
                return existing, nil
        }
 
+       now := time.Now().UTC()
        p := &model.Project{
                ID:          projectID,
                GrantNumber: grantNumber,
                IsActive:    true,
+               CreatedAt:   now,
+               UpdatedAt:   now,
        }
 
        if err := s.projects.Save(ctx, tx, p); err != nil {
diff --git a/allocations/access-amie/store/audit_store.go 
b/allocations/access-amie/store/audit_store.go
index 5a06e15df..709c03446 100644
--- a/allocations/access-amie/store/audit_store.go
+++ b/allocations/access-amie/store/audit_store.go
@@ -39,7 +39,7 @@ func NewAuditStore(db *sqlx.DB) AuditStore {
 
 func (s *mariaDBauditStore) Save(ctx context.Context, tx *sql.Tx, a 
*model.AuditLog) error {
        _, err := tx.ExecContext(ctx,
-               `INSERT INTO amie_audit_logs (packet_id, event_id, action, 
entity_type, entity_id, summary, created_at)
+               `INSERT INTO amie_audit_log (packet_id, event_id, action, 
entity_type, entity_id, summary, created_at)
                 VALUES (?, ?, ?, ?, ?, ?, ?)`,
                a.PacketID, a.EventID, a.Action, a.EntityType, a.EntityID, 
a.Summary, a.CreatedAt)
        return err
diff --git a/allocations/access-amie/worker/processor.go 
b/allocations/access-amie/worker/processor.go
index 2535a6269..99ee80804 100644
--- a/allocations/access-amie/worker/processor.go
+++ b/allocations/access-amie/worker/processor.go
@@ -97,7 +97,6 @@ func (p *Processor) Run(ctx context.Context) {
        ticker := time.NewTicker(p.workerInterval)
        defer ticker.Stop()
 
-       // Process immediately on start, then on ticker.
        p.processPendingEvents(ctx)
        for {
                select {
@@ -159,7 +158,6 @@ func (p *Processor) executeInTransaction(ctx 
context.Context, ewp model.EventWit
                        "attempt", ewp.Attempts+1,
                )
 
-               // Mark the event as RUNNING and increment the attempt counter.
                now := time.Now().UTC()
                ewp.Status = model.ProcessingStatusRunning
                ewp.StartedAt = &now
@@ -168,26 +166,21 @@ func (p *Processor) executeInTransaction(ctx 
context.Context, ewp model.EventWit
                        return fmt.Errorf("update event to RUNNING: %w", err)
                }
 
-               // Parse the packet's raw JSON.
                var packetJSON map[string]any
                if err := json.Unmarshal([]byte(ewp.PacketRawJSON), 
&packetJSON); err != nil {
                        return fmt.Errorf("unmarshal packet raw JSON: %w", err)
                }
 
-               // Build a Packet from the EventWithPacket projection fields.
-               packet := &model.Packet{
-                       ID:      ewp.PacketID,
-                       AmieID:  ewp.PacketAmieID,
-                       Type:    ewp.PacketType,
-                       RawJSON: ewp.PacketRawJSON,
+               // Load the full packet from DB to preserve all fields (e.g. 
retries).
+               packet, err := p.packetStore.FindByID(ctx, ewp.PacketID)
+               if err != nil {
+                       return fmt.Errorf("load packet %s: %w", ewp.PacketID, 
err)
                }
 
-               // Route the packet to its handler.
                if err := p.router.Route(ctx, tx, packetJSON, packet, ewp.ID); 
err != nil {
                        return fmt.Errorf("route packet: %w", err)
                }
 
-               // Mark the event as SUCCEEDED.
                finishedAt := time.Now().UTC()
                ewp.Status = model.ProcessingStatusSucceeded
                ewp.FinishedAt = &finishedAt
@@ -196,7 +189,6 @@ func (p *Processor) executeInTransaction(ctx 
context.Context, ewp model.EventWit
                        return fmt.Errorf("update event to SUCCEEDED: %w", err)
                }
 
-               // Mark the packet as DECODED.
                decodedAt := time.Now().UTC()
                packet.Status = model.PacketStatusDecoded
                packet.DecodedAt = &decodedAt
@@ -227,7 +219,6 @@ func (p *Processor) recordFailureInNewTransaction(ctx 
context.Context, eventID s
                        return nil
                }
 
-               // Load the associated packet.
                packet, err := p.packetStore.FindByID(ctx, event.PacketID)
                if err != nil {
                        return fmt.Errorf("find packet for failure recording: 
%w", err)
@@ -248,6 +239,13 @@ func (p *Processor) recordFailureInNewTransaction(ctx 
context.Context, eventID s
                        event.Status = model.ProcessingStatusRetryScheduled
                        nextRetry := ComputeNextRetryAt(effectiveAttempts)
                        event.NextRetryAt = &nextRetry
+
+                       packet.Retries = effectiveAttempts
+                       packet.LastError = &errMsg
+                       if err := p.packetStore.Update(ctx, tx, packet); err != 
nil {
+                               return fmt.Errorf("update packet retries: %w", 
err)
+                       }
+
                        p.metrics.RecordRetry()
                        p.metrics.RecordPacketProcessed(packet.Type, 
"retry_scheduled")
                        slog.Warn("event failed, scheduling retry",
@@ -261,8 +259,8 @@ func (p *Processor) recordFailureInNewTransaction(ctx 
context.Context, eventID s
                        p.metrics.RecordPacketProcessed(packet.Type, 
"permanently_failed")
                        slog.Error("event permanently failed after max 
attempts", "eventId", eventID)
 
-                       // Mark the packet as FAILED.
                        packet.Status = model.PacketStatusFailed
+                       packet.Retries = effectiveAttempts
                        packet.LastError = &errMsg
                        if err := p.packetStore.Update(ctx, tx, packet); err != 
nil {
                                return fmt.Errorf("update packet status: %w", 
err)
@@ -273,7 +271,6 @@ func (p *Processor) recordFailureInNewTransaction(ctx 
context.Context, eventID s
                        return fmt.Errorf("update event: %w", err)
                }
 
-               // Create a processing error record.
                detail := cause.Error()
                if len(detail) > 8000 {
                        detail = detail[:8000]
diff --git a/allocations/domain/model/person.go 
b/allocations/domain/model/person.go
index 1b1b65382..00a9c7f0e 100644
--- a/allocations/domain/model/person.go
+++ b/allocations/domain/model/person.go
@@ -28,10 +28,17 @@ type Person struct {
        Organization   *string   `db:"organization" 
json:"organization,omitempty"`
        OrgCode        *string   `db:"org_code" json:"org_code,omitempty"`
        NsfStatusCode  *string   `db:"nsf_status_code" 
json:"nsf_status_code,omitempty"`
+       IsActive       bool      `db:"is_active" json:"is_active"`
        CreatedAt      time.Time `db:"created_at" json:"created_at"`
        UpdatedAt      time.Time `db:"updated_at" json:"updated_at"`
 }
 
+type PersonGlobalID struct {
+       ID       int64  `db:"id" json:"id"`
+       PersonID string `db:"person_id" json:"person_id"`
+       GlobalID string `db:"global_id" json:"global_id"`
+}
+
 type PersonDN struct {
        ID       int64  `db:"id" json:"id"`
        PersonID string `db:"person_id" json:"person_id"`
diff --git a/allocations/domain/store/person_store.go 
b/allocations/domain/store/person_store.go
index 00122edf5..4b7861230 100644
--- a/allocations/domain/store/person_store.go
+++ b/allocations/domain/store/person_store.go
@@ -21,11 +21,14 @@ import (
        "context"
        "database/sql"
        "errors"
+       "time"
 
        "github.com/apache/airavata-custos/allocations/domain/model"
        "github.com/jmoiron/sqlx"
 )
 
+const personColumns = `id, access_global_id, first_name, last_name, email, 
organization, org_code, nsf_status_code, is_active, created_at, updated_at`
+
 type mariaDBPersonStore struct {
        db *sqlx.DB
 }
@@ -37,8 +40,7 @@ func NewPersonStore(db *sqlx.DB) PersonStore {
 func (s *mariaDBPersonStore) FindByID(ctx context.Context, id string) 
(*model.Person, error) {
        var p model.Person
        err := s.db.GetContext(ctx, &p,
-               `SELECT id, access_global_id, first_name, last_name, email, 
organization, org_code, nsf_status_code, created_at, updated_at
-                FROM persons WHERE id = ?`, id)
+               `SELECT `+personColumns+` FROM persons WHERE id = ?`, id)
        if err != nil {
                if errors.Is(err, sql.ErrNoRows) {
                        return nil, nil
@@ -51,8 +53,20 @@ func (s *mariaDBPersonStore) FindByID(ctx context.Context, 
id string) (*model.Pe
 func (s *mariaDBPersonStore) FindByAccessGlobalID(ctx context.Context, 
globalID string) (*model.Person, error) {
        var p model.Person
        err := s.db.GetContext(ctx, &p,
-               `SELECT id, access_global_id, first_name, last_name, email, 
organization, org_code, nsf_status_code, created_at, updated_at
-                FROM persons WHERE access_global_id = ?`, globalID)
+               `SELECT `+personColumns+` FROM persons WHERE access_global_id = 
?`, globalID)
+       if err != nil {
+               if errors.Is(err, sql.ErrNoRows) {
+                       return nil, nil
+               }
+               return nil, err
+       }
+       return &p, nil
+}
+
+func (s *mariaDBPersonStore) FindActiveByEmail(ctx context.Context, email 
string) (*model.Person, error) {
+       var p model.Person
+       err := s.db.GetContext(ctx, &p,
+               `SELECT `+personColumns+` FROM persons WHERE email = ? AND 
is_active = TRUE LIMIT 1`, email)
        if err != nil {
                if errors.Is(err, sql.ErrNoRows) {
                        return nil, nil
@@ -64,14 +78,32 @@ func (s *mariaDBPersonStore) FindByAccessGlobalID(ctx 
context.Context, globalID
 
 func (s *mariaDBPersonStore) Save(ctx context.Context, tx *sql.Tx, p 
*model.Person) error {
        _, err := tx.ExecContext(ctx,
-               `INSERT INTO persons (id, access_global_id, first_name, 
last_name, email, organization, org_code, nsf_status_code, created_at, 
updated_at)
-                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
+               `INSERT INTO persons (id, access_global_id, first_name, 
last_name, email, organization, org_code, nsf_status_code, is_active, 
created_at, updated_at)
+                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
                p.ID, p.AccessGlobalID, p.FirstName, p.LastName, p.Email,
-               p.Organization, p.OrgCode, p.NsfStatusCode,
+               p.Organization, p.OrgCode, p.NsfStatusCode, p.IsActive,
                p.CreatedAt, p.UpdatedAt)
        return err
 }
 
+func (s *mariaDBPersonStore) Update(ctx context.Context, tx *sql.Tx, p 
*model.Person) error {
+       _, err := tx.ExecContext(ctx,
+               `UPDATE persons SET access_global_id = ?, first_name = ?, 
last_name = ?, email = ?,
+                  organization = ?, org_code = ?, nsf_status_code = ?, 
is_active = ?, updated_at = ?
+                WHERE id = ?`,
+               p.AccessGlobalID, p.FirstName, p.LastName, p.Email,
+               p.Organization, p.OrgCode, p.NsfStatusCode, p.IsActive,
+               p.UpdatedAt, p.ID)
+       return err
+}
+
+func (s *mariaDBPersonStore) Deactivate(ctx context.Context, tx *sql.Tx, id 
string) error {
+       _, err := tx.ExecContext(ctx,
+               `UPDATE persons SET is_active = FALSE, updated_at = ? WHERE id 
= ?`,
+               time.Now().UTC(), id)
+       return err
+}
+
 func (s *mariaDBPersonStore) Delete(ctx context.Context, tx *sql.Tx, id 
string) error {
        _, err := tx.ExecContext(ctx,
                `DELETE FROM persons WHERE id = ?`, id)
diff --git a/allocations/domain/store/stores.go 
b/allocations/domain/store/stores.go
index 786119497..d009a6450 100644
--- a/allocations/domain/store/stores.go
+++ b/allocations/domain/store/stores.go
@@ -27,10 +27,19 @@ import (
 type PersonStore interface {
        FindByID(ctx context.Context, id string) (*model.Person, error)
        FindByAccessGlobalID(ctx context.Context, globalID string) 
(*model.Person, error)
+       FindActiveByEmail(ctx context.Context, email string) (*model.Person, 
error)
        Save(ctx context.Context, tx *sql.Tx, p *model.Person) error
+       Update(ctx context.Context, tx *sql.Tx, p *model.Person) error
+       Deactivate(ctx context.Context, tx *sql.Tx, id string) error
        Delete(ctx context.Context, tx *sql.Tx, id string) error
 }
 
+type PersonGlobalIDStore interface {
+       FindPersonByGlobalID(ctx context.Context, globalID string) 
(*model.Person, error)
+       Save(ctx context.Context, tx *sql.Tx, g *model.PersonGlobalID) error
+       UpdatePersonID(ctx context.Context, tx *sql.Tx, oldPersonID, 
newPersonID string) error
+}
+
 type PersonDNStore interface {
        ExistsByPersonAndDN(ctx context.Context, personID, dn string) (bool, 
error)
        Save(ctx context.Context, tx *sql.Tx, d *model.PersonDN) error
diff --git a/allocations/go.work.sum b/allocations/go.work.sum
new file mode 100644
index 000000000..6390a5c4f
--- /dev/null
+++ b/allocations/go.work.sum
@@ -0,0 +1,451 @@
+cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM=
+cloud.google.com/go v0.112.1/go.mod 
h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4=
+cloud.google.com/go/compute v1.25.1 
h1:ZRpHJedLtTpKgr3RV1Fx23NuaAEN1Zfx9hw1u4aJdjU=
+cloud.google.com/go/compute v1.25.1/go.mod 
h1:oopOIR53ly6viBYxaDhBfJwzUAxf1zE//uf3IB011ls=
+cloud.google.com/go/compute/metadata v0.2.3 
h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
+cloud.google.com/go/compute/metadata v0.2.3/go.mod 
h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
+cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc=
+cloud.google.com/go/iam v1.1.6/go.mod 
h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI=
+cloud.google.com/go/longrunning v0.5.5 
h1:GOE6pZFdSrTb4KAiKnXsJBtlE6mEyaW44oKyMILWnOg=
+cloud.google.com/go/longrunning v0.5.5/go.mod 
h1:WV2LAxD8/rg5Z1cNW6FJ/ZpX4E4VnDnoTk0yawPBB7s=
+cloud.google.com/go/spanner v1.56.0 
h1:o/Cv7/zZ1WgRXVCd5g3Nc23ZI39p/1pWFqFwvg6Wcu8=
+cloud.google.com/go/spanner v1.56.0/go.mod 
h1:DndqtUKQAt3VLuV2Le+9Y3WTnq5cNKrnLb/Piqcj+h0=
+cloud.google.com/go/storage v1.38.0 
h1:Az68ZRGlnNTpIBbLjSMIV2BDcwwXYlRlQzis0llkpJg=
+cloud.google.com/go/storage v1.38.0/go.mod 
h1:tlUADB0mAb9BgYls9lq+8MGkfzOXuLrnHXlpHmvFJoY=
+filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
+filippo.io/edwards25519 v1.1.0/go.mod 
h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
+github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 
h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs=
+github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod 
h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4=
+github.com/99designs/keyring v1.2.1 
h1:tYLp1ULvO7i3fI5vE21ReQuj99QFSs7lGm0xWyJo87o=
+github.com/99designs/keyring v1.2.1/go.mod 
h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0 
h1:rTnT/Jrcm+figWlYz4Ixzt0SJVR2cMC8lvZcimipiEY=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0/go.mod 
h1:ON4tFdPTwRcgWEaVDrN3584Ef+b7GgSJaXxe5fW9t4M=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2 
h1:+5VZ72z0Qan5Bog5C+ZkgSqUbeVUd9wgtHOrIKuc5b8=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2/go.mod 
h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
+github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0 
h1:u/LLAOFgsMv7HmNL4Qufg58y+qElGOt5qv0z1mURkRY=
+github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0/go.mod 
h1:2e8rMJtl2+2j+HXbTBwnyGpm5Nou7KhvSfxOq8JpTag=
+github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 
h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
+github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod 
h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
+github.com/Azure/go-autorest v14.2.0+incompatible 
h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
+github.com/Azure/go-autorest v14.2.0+incompatible/go.mod 
h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
+github.com/Azure/go-autorest/autorest/adal v0.9.16 
h1:P8An8Z9rH1ldbOLdFpxYorgOt2sywL9V24dAwWHPuGc=
+github.com/Azure/go-autorest/autorest/adal v0.9.16/go.mod 
h1:tGMin8I49Yij6AQ+rvV+Xa/zwxYQB5hmsd6DkfAx2+A=
+github.com/Azure/go-autorest/autorest/date v0.3.0 
h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=
+github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod 
h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
+github.com/Azure/go-autorest/logger v0.2.1 
h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg=
+github.com/Azure/go-autorest/logger v0.2.1/go.mod 
h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
+github.com/Azure/go-autorest/tracing v0.6.0 
h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
+github.com/Azure/go-autorest/tracing v0.6.0/go.mod 
h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
+github.com/ClickHouse/clickhouse-go v1.4.3 
h1:iAFMa2UrQdR5bHJ2/yaSLffZkxpcOYQMCUuKeNXGdqc=
+github.com/ClickHouse/clickhouse-go v1.4.3/go.mod 
h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=
+github.com/Microsoft/go-winio v0.6.2 
h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
+github.com/Microsoft/go-winio v0.6.2/go.mod 
h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
+github.com/alecthomas/kingpin/v2 v2.4.0 
h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY=
+github.com/alecthomas/kingpin/v2 v2.4.0/go.mod 
h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE=
+github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 
h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc=
+github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod 
h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
+github.com/andybalholm/brotli v1.0.4 
h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
+github.com/andybalholm/brotli v1.0.4/go.mod 
h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
+github.com/apache/arrow/go/v10 v10.0.1 
h1:n9dERvixoC/1JjDmBcs9FPaEryoANa2sCgVFo6ez9cI=
+github.com/apache/arrow/go/v10 v10.0.1/go.mod 
h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0=
+github.com/apache/thrift v0.16.0 
h1:qEy6UW60iVOlUy+b9ZR0d5WzUWYGOo4HfopoyBaNmoY=
+github.com/apache/thrift v0.16.0/go.mod 
h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU=
+github.com/aws/aws-sdk-go v1.49.6 
h1:yNldzF5kzLBRvKlKz1S0bkvc2+04R1kt13KfBWQBfFA=
+github.com/aws/aws-sdk-go v1.49.6/go.mod 
h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
+github.com/aws/aws-sdk-go-v2 v1.16.16 
h1:M1fj4FE2lB4NzRb9Y0xdWsn2P0+2UHVxwKyOa4YJNjk=
+github.com/aws/aws-sdk-go-v2 v1.16.16/go.mod 
h1:SwiyXi/1zTUZ6KIAmLK5V5ll8SiURNUYOqTerZPaF9k=
+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.8 
h1:tcFliCWne+zOuUfKNRn8JdFBuWPDuISDH08wD2ULkhk=
+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.8/go.mod 
h1:JTnlBSot91steJeti4ryyu/tLd4Sk84O5W22L7O2EQU=
+github.com/aws/aws-sdk-go-v2/credentials v1.12.20 
h1:9+ZhlDY7N9dPnUmf7CDfW9In4sW5Ff3bh7oy4DzS1IE=
+github.com/aws/aws-sdk-go-v2/credentials v1.12.20/go.mod 
h1:UKY5HyIux08bbNA7Blv4PcXQ8cTkGh7ghHMFklaviR4=
+github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.33 
h1:fAoVmNGhir6BR+RU0/EI+6+D7abM+MCwWf8v4ip5jNI=
+github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.33/go.mod 
h1:84XgODVR8uRhmOnUkKGUZKqIMxmjmLOR8Uyp7G/TPwc=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.23 
h1:s4g/wnzMf+qepSNgTvaQQHNxyMLKSawNhKCPNy++2xY=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.23/go.mod 
h1:2DFxAQ9pfIRy0imBCJv+vZ2X6RKxves6fbnEuSry6b4=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.17 
h1:/K482T5A3623WJgWT8w1yRAFK4RzGzEl7y39yhtn9eA=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.17/go.mod 
h1:pRwaTYCJemADaqCbUAxltMoHKata7hmB5PjEXeu0kfg=
+github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.14 
h1:ZSIPAkAsCCjYrhqfw2+lNzWDzxzHXEckFkTePL5RSWQ=
+github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.14/go.mod 
h1:AyGgqiKv9ECM6IZeNQtdT8NnMvUb3/2wokeq2Fgryto=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.9 
h1:Lh1AShsuIJTwMkoxVCAYPJgNG5H+eN6SmoUn8nOZ5wE=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.9/go.mod 
h1:a9j48l6yL5XINLHLcOKInjdvknN+vWqPBxqeIDw7ktw=
+github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.18 
h1:BBYoNQt2kUZUUK4bIPsKrCcjVPUMNsgQpNAwhznK/zo=
+github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.18/go.mod 
h1:NS55eQ4YixUJPTC+INxi2/jCqe1y2Uw3rnh9wEOVJxY=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.17 
h1:Jrd/oMh0PKQc6+BowB+pLEwLIgaQF29eYbe7E1Av9Ug=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.17/go.mod 
h1:4nYOrY41Lrbk2170/BGkcJKBhws9Pfn8MG3aGqjjeFI=
+github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.17 
h1:HfVVR1vItaG6le+Bpw6P4midjBDMKnjMyZnw9MXYUcE=
+github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.17/go.mod 
h1:YqMdV+gEKCQ59NrB7rzrJdALeBIsYiVi8Inj3+KcqHI=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.27.11 
h1:3/gm/JTX9bX8CpzTgIlrtYpB3EVBDxyg/GY/QdcIEZw=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.27.11/go.mod 
h1:fmgDANqTUCxciViKl9hb/zD5LFbvPINFRgWhDbR+vZo=
+github.com/aws/smithy-go v1.13.3 
h1:l7LYxGuzK6/K+NzJ2mC+VvLUbae0sL3bXU//04MkmnA=
+github.com/aws/smithy-go v1.13.3/go.mod 
h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
+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/cenkalti/backoff/v4 v4.1.2 
h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo=
+github.com/cenkalti/backoff/v4 v4.1.2/go.mod 
h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
+github.com/census-instrumentation/opencensus-proto v0.4.1 
h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g=
+github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod 
h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
+github.com/cespare/xxhash/v2 v2.3.0 
h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
+github.com/cespare/xxhash/v2 v2.3.0/go.mod 
h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 
h1:F1EaeKL/ta07PY/k9Os/UFtwERei2/XzGemhpGnBKNg=
+github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod 
h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
+github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50 
h1:DBmgJDC9dTfkVyGgipamEh2BpGYxScCH1TOF1LL1cXc=
+github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50/go.mod 
h1:5e1+Vvlzido69INQaVO6d87Qn543Xr6nooe9Kz7oBFM=
+github.com/cockroachdb/cockroach-go/v2 v2.1.1 
h1:3XzfSMuUT0wBe1a3o5C0eOTcArhmmFAg2Jzh/7hhKqo=
+github.com/cockroachdb/cockroach-go/v2 v2.1.1/go.mod 
h1:7NtUnP6eK+l6k483WSYNrq3Kb23bWV10IRV1TyeSpwM=
+github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369 
h1:XNT/Zf5l++1Pyg08/HV04ppB0gKxAqtZQBRYiYrUuYk=
+github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369/go.mod 
h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=
+github.com/danieljoos/wincred v1.1.2 
h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0=
+github.com/danieljoos/wincred v1.1.2/go.mod 
h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0=
+github.com/davecgh/go-spew v1.1.0/go.mod 
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 
h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod 
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dhui/dktest v0.4.3 h1:wquqUxAFdcUgabAVLvSCOKOlag5cIZuaOjYIBOWdsR0=
+github.com/dhui/dktest v0.4.3/go.mod 
h1:zNK8IwktWzQRm6I/l2Wjp7MakiyaFWv4G1hjmodmMTs=
+github.com/distribution/reference v0.6.0 
h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
+github.com/distribution/reference v0.6.0/go.mod 
h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
+github.com/docker/docker v27.2.0+incompatible 
h1:Rk9nIVdfH3+Vz4cyI/uhbINhEZ/oLmc+CBXmH6fbNk4=
+github.com/docker/docker v27.2.0+incompatible/go.mod 
h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/go-connections v0.5.0 
h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
+github.com/docker/go-connections v0.5.0/go.mod 
h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
+github.com/docker/go-units v0.5.0 
h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
+github.com/docker/go-units v0.5.0/go.mod 
h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
+github.com/dvsekhvalnov/jose2go v1.6.0 
h1:Y9gnSnP4qEI0+/uQkHvFXeD2PLPJeXEL+ySMEA2EjTY=
+github.com/dvsekhvalnov/jose2go v1.6.0/go.mod 
h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU=
+github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712 
h1:aaQcKT9WumO6JEJcRyTqFVq4XUZiUcKR2/GI31TOcz8=
+github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod 
h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
+github.com/envoyproxy/go-control-plane v0.12.0 
h1:4X+VP1GHd1Mhj6IB5mMeGbLCleqxjletLK6K0rbxyZI=
+github.com/envoyproxy/go-control-plane v0.12.0/go.mod 
h1:ZBTaoJ23lqITozF0M6G4/IragXCQKCnYbmlmtHvwRG0=
+github.com/envoyproxy/protoc-gen-validate v1.0.4 
h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A=
+github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod 
h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew=
+github.com/felixge/httpsnoop v1.0.4 
h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
+github.com/felixge/httpsnoop v1.0.4/go.mod 
h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
+github.com/form3tech-oss/jwt-go v3.2.5+incompatible 
h1:/l4kBbb4/vGSsdtB5nUe8L7B9mImVMaBPw9L/0TBHU8=
+github.com/form3tech-oss/jwt-go v3.2.5+incompatible/go.mod 
h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
+github.com/fsouza/fake-gcs-server v1.17.0 
h1:OeH75kBZcZa3ZE+zz/mFdJ2btt9FgqfjI7gIh9+5fvk=
+github.com/fsouza/fake-gcs-server v1.17.0/go.mod 
h1:D1rTE4YCyHFNa99oyJJ5HyclvN/0uQR+pM/VdlL83bw=
+github.com/gabriel-vasile/mimetype v1.4.1 
h1:TRWk7se+TOjCYgRth7+1/OYLNiRNIotknkFtf/dnN7Q=
+github.com/gabriel-vasile/mimetype v1.4.1/go.mod 
h1:05Vi0w3Y9c/lNvJOdmIwvrrAhX3rYhfQQCaf9VJcv7M=
+github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
+github.com/go-kit/log v0.2.1/go.mod 
h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
+github.com/go-logfmt/logfmt v0.5.1 
h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
+github.com/go-logfmt/logfmt v0.5.1/go.mod 
h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
+github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
+github.com/go-logr/logr v1.4.2/go.mod 
h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod 
h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/go-sql-driver/mysql v1.8.1 
h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
+github.com/go-sql-driver/mysql v1.8.1/go.mod 
h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
+github.com/go-stack/stack v1.8.0 
h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
+github.com/go-stack/stack v1.8.0/go.mod 
h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gobuffalo/here v0.6.0 
h1:hYrd0a6gDmWxBM4TnrGw8mQg24iSVoIkHEk7FodQcBI=
+github.com/gobuffalo/here v0.6.0/go.mod 
h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM=
+github.com/goccy/go-json v0.9.11 
h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
+github.com/goccy/go-json v0.9.11/go.mod 
h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/gocql/gocql v0.0.0-20210515062232-b7ef815b4556 
h1:N/MD/sr6o61X+iZBAT2qEUF023s4KbA8RWfKzl0L6MQ=
+github.com/gocql/gocql v0.0.0-20210515062232-b7ef815b4556/go.mod 
h1:DL0ekTmBSTdlNF25Orwt/JMzqIq3EJ4MVa/J/uK64OY=
+github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 
h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0=
+github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod 
h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod 
h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang-jwt/jwt/v4 v4.4.2 
h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs=
+github.com/golang-jwt/jwt/v4 v4.4.2/go.mod 
h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
+github.com/golang-migrate/migrate/v4 v4.18.1 
h1:JML/k+t4tpHCpQTCAD62Nu43NUFzHY4CV3uAuvHGC+Y=
+github.com/golang-migrate/migrate/v4 v4.18.1/go.mod 
h1:HAX6m3sQgcdO81tdjn5exv20+3Kb13cmGli1hrD6hks=
+github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe 
h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
+github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod 
h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
+github.com/golang-sql/sqlexp v0.1.0 
h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
+github.com/golang-sql/sqlexp v0.1.0/go.mod 
h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da 
h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod 
h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/protobuf v1.5.4 
h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod 
h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
+github.com/golang/snappy v0.0.4/go.mod 
h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/google/flatbuffers v2.0.8+incompatible 
h1:ivUb1cGomAB101ZM1T0nOiWz9pSrTMoa9+EiY7igmkM=
+github.com/google/flatbuffers v2.0.8+incompatible/go.mod 
h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod 
h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-github/v39 v39.2.0 
h1:rNNM311XtPOz5rDdsJXAp2o8F67X9FnROXTvto3aSnQ=
+github.com/google/go-github/v39 v39.2.0/go.mod 
h1:C1s8C5aCC9L+JXIYpJM5GYytdX52vC1bLvHEF1IhBrE=
+github.com/google/go-querystring v1.1.0 
h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
+github.com/google/go-querystring v1.1.0/go.mod 
h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
+github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
+github.com/google/s2a-go v0.1.7/go.mod 
h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod 
h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/googleapis/enterprise-certificate-proxy v0.3.2 
h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
+github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod 
h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
+github.com/googleapis/gax-go/v2 v2.12.2 
h1:mhN09QQW1jEWeMF74zGR81R30z4VJzjZsfkUhuHF+DA=
+github.com/googleapis/gax-go/v2 v2.12.2/go.mod 
h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc=
+github.com/gorilla/handlers v1.4.2 
h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg=
+github.com/gorilla/handlers v1.4.2/go.mod 
h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
+github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc=
+github.com/gorilla/mux v1.7.4/go.mod 
h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
+github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c 
h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU=
+github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod 
h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0=
+github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed 
h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=
+github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod 
h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
+github.com/hashicorp/errwrap v1.0.0/go.mod 
h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/errwrap v1.1.0 
h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
+github.com/hashicorp/errwrap v1.1.0/go.mod 
h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-multierror v1.1.1 
h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
+github.com/hashicorp/go-multierror v1.1.1/go.mod 
h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
+github.com/jackc/chunkreader/v2 v2.0.1 
h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
+github.com/jackc/chunkreader/v2 v2.0.1/go.mod 
h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
+github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w=
+github.com/jackc/pgconn v1.14.3/go.mod 
h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM=
+github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa 
h1:s+4MhCQ6YrzisK6hFJUX53drDT4UsSW3DEhKn0ifuHw=
+github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa/go.mod 
h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds=
+github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
+github.com/jackc/pgio v1.0.0/go.mod 
h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
+github.com/jackc/pgpassfile v1.0.0 
h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
+github.com/jackc/pgpassfile v1.0.0/go.mod 
h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
+github.com/jackc/pgproto3/v2 v2.3.3 
h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag=
+github.com/jackc/pgproto3/v2 v2.3.3/go.mod 
h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
+github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a 
h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
+github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod 
h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
+github.com/jackc/pgtype v1.14.0 h1:y+xUdabmyMkJLyApYuPj38mW+aAIqCe5uuBB51rH3Vw=
+github.com/jackc/pgtype v1.14.0/go.mod 
h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
+github.com/jackc/pgx/v4 v4.18.2 h1:xVpYkNR5pk5bMCZGfClbO962UIqVABcAGt7ha1s/FeU=
+github.com/jackc/pgx/v4 v4.18.2/go.mod 
h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw=
+github.com/jackc/pgx/v5 v5.5.4 h1:Xp2aQS8uXButQdnCMWNmvx6UysWQQC+u1EoizjguY+8=
+github.com/jackc/pgx/v5 v5.5.4/go.mod 
h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
+github.com/jackc/puddle/v2 v2.2.1 
h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
+github.com/jackc/puddle/v2 v2.2.1/go.mod 
h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
+github.com/jmespath/go-jmespath v0.4.0 
h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
+github.com/jmespath/go-jmespath v0.4.0/go.mod 
h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
+github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
+github.com/jmoiron/sqlx v1.4.0/go.mod 
h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
+github.com/jpillora/backoff v1.0.0 
h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
+github.com/jpillora/backoff v1.0.0/go.mod 
h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
+github.com/json-iterator/go v1.1.12 
h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod 
h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/julienschmidt/httprouter v1.3.0 
h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
+github.com/julienschmidt/httprouter v1.3.0/go.mod 
h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
+github.com/k0kubun/pp v2.3.0+incompatible 
h1:EKhKbi34VQDWJtq+zpsKSEhkHHs9w2P8Izbq8IhLVSo=
+github.com/k0kubun/pp v2.3.0+incompatible/go.mod 
h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg=
+github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 
h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA=
+github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod 
h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
+github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 
h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
+github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod 
h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
+github.com/klauspost/asmfmt v1.3.2 
h1:4Ri7ox3EwapiOjCki+hw14RyKk201CN4rzyCJRFLpK4=
+github.com/klauspost/asmfmt v1.3.2/go.mod 
h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE=
+github.com/klauspost/compress v1.17.9 
h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
+github.com/klauspost/compress v1.17.9/go.mod 
h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
+github.com/klauspost/cpuid/v2 v2.0.9 
h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
+github.com/klauspost/cpuid/v2 v2.0.9/go.mod 
h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod 
h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod 
h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/ktrysmt/go-bitbucket v0.6.4 
h1:C8dUGp0qkwncKtAnozHCbbqhptefzEd1I0sfnuy9rYQ=
+github.com/ktrysmt/go-bitbucket v0.6.4/go.mod 
h1:9u0v3hsd2rqCHRIpbir1oP7F58uo5dq19sBYvuMoyQ4=
+github.com/kylelemons/godebug v1.1.0 
h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
+github.com/kylelemons/godebug v1.1.0/go.mod 
h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
+github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
+github.com/lib/pq v1.10.9/go.mod 
h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/markbates/pkger v0.15.1 
h1:3MPelV53RnGSW07izx5xGxl4e/sdRD6zqseIk0rMASY=
+github.com/markbates/pkger v0.15.1/go.mod 
h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI=
+github.com/mattn/go-colorable v0.1.6 
h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
+github.com/mattn/go-colorable v0.1.6/go.mod 
h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-isatty v0.0.16 
h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
+github.com/mattn/go-isatty v0.0.16/go.mod 
h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-sqlite3 v1.14.22 
h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
+github.com/mattn/go-sqlite3 v1.14.22/go.mod 
h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
+github.com/microsoft/go-mssqldb v1.0.0 
h1:k2p2uuG8T5T/7Hp7/e3vMGTnnR0sU4h8d1CcC71iLHU=
+github.com/microsoft/go-mssqldb v1.0.0/go.mod 
h1:+4wZTUnz/SV6nffv+RRRB/ss8jPng5Sho2SmM1l2ts4=
+github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 
h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs=
+github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod 
h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY=
+github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 
h1:+n/aFZefKZp7spd8DFdX7uMikMLXX4oubIzJF4kv/wI=
+github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod 
h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE=
+github.com/mitchellh/mapstructure v1.1.2 
h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
+github.com/mitchellh/mapstructure v1.1.2/go.mod 
h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/moby/docker-image-spec v1.3.1 
h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
+github.com/moby/docker-image-spec v1.3.1/go.mod 
h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
+github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
+github.com/moby/term v0.5.0/go.mod 
h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd 
h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod 
h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.2 
h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod 
h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
+github.com/morikuni/aec v1.0.0/go.mod 
h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
+github.com/mtibben/percent v0.2.1 
h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs=
+github.com/mtibben/percent v0.2.1/go.mod 
h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 
h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod 
h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/mutecomm/go-sqlcipher/v4 v4.4.0 
h1:sV1tWCWGAVlPhNGT95Q+z/txFxuhAYWwHD1afF5bMZg=
+github.com/mutecomm/go-sqlcipher/v4 v4.4.0/go.mod 
h1:PyN04SaWalavxRGH9E8ZftG6Ju7rsPrGmQRjrEaVpiY=
+github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f 
h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
+github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod 
h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8 
h1:P48LjvUQpTReR3TQRbxSeSBsMXzfK0uol7eRcr7VBYQ=
+github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8/go.mod 
h1:86wM1zFnC6/uDBfZGNwB65O+pR2OFi5q/YQaEUid1qA=
+github.com/neo4j/neo4j-go-driver v1.8.1-0.20200803113522-b626aa943eba 
h1:fhFP5RliM2HW/8XdcO5QngSfFli9GcRIpMXvypTQt6E=
+github.com/neo4j/neo4j-go-driver v1.8.1-0.20200803113522-b626aa943eba/go.mod 
h1:ncO5VaFWh0Nrt+4KT4mOZboaczBZcLuHrG+/sUeP8gI=
+github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
+github.com/onsi/ginkgo v1.16.4/go.mod 
h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
+github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU=
+github.com/onsi/gomega v1.15.0/go.mod 
h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
+github.com/opencontainers/go-digest v1.0.0 
h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
+github.com/opencontainers/go-digest v1.0.0/go.mod 
h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
+github.com/opencontainers/image-spec v1.1.0 
h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
+github.com/opencontainers/image-spec v1.1.0/go.mod 
h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
+github.com/pierrec/lz4/v4 v4.1.16 
h1:kQPfno+wyx6C5572ABwV+Uo3pDFzQ7yhyGchSyRda0c=
+github.com/pierrec/lz4/v4 v4.1.16/go.mod 
h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
+github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 
h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
+github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod 
h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod 
h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 
h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod 
h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_golang v1.20.5 
h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
+github.com/prometheus/client_golang v1.20.5/go.mod 
h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
+github.com/prometheus/client_model v0.6.1 
h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
+github.com/prometheus/client_model v0.6.1/go.mod 
h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
+github.com/prometheus/common v0.55.0 
h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
+github.com/prometheus/common v0.55.0/go.mod 
h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
+github.com/prometheus/procfs v0.15.1 
h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
+github.com/prometheus/procfs v0.15.1/go.mod 
h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
+github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 
h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
+github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod 
h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
+github.com/rogpeppe/go-internal v1.12.0 
h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
+github.com/rogpeppe/go-internal v1.12.0/go.mod 
h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
+github.com/rqlite/gorqlite v0.0.0-20230708021416-2acd02b70b79 
h1:V7x0hCAgL8lNGezuex1RW1sh7VXXCqfw8nXZti66iFg=
+github.com/rqlite/gorqlite v0.0.0-20230708021416-2acd02b70b79/go.mod 
h1:xF/KoXmrRyahPfo5L7Szb5cAAUl53dMWBh9cMruGEZg=
+github.com/shopspring/decimal v1.2.0 
h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
+github.com/shopspring/decimal v1.2.0/go.mod 
h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
+github.com/sirupsen/logrus v1.9.3 
h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
+github.com/sirupsen/logrus v1.9.3/go.mod 
h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/snowflakedb/gosnowflake v1.6.19 
h1:KSHXrQ5o7uso25hNIzi/RObXtnSGkFgie91X82KcvMY=
+github.com/snowflakedb/gosnowflake v1.6.19/go.mod 
h1:FM1+PWUdwB9udFDsXdfD58NONC0m+MlOSmQRvimobSM=
+github.com/stretchr/objx v0.1.0/go.mod 
h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
+github.com/stretchr/objx v0.5.2/go.mod 
h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
+github.com/stretchr/testify v1.3.0/go.mod 
h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.10.0 
h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
+github.com/stretchr/testify v1.10.0/go.mod 
h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/xanzy/go-gitlab v0.15.0 
h1:rWtwKTgEnXyNUGrOArN7yyc3THRkpYcKXIXia9abywQ=
+github.com/xanzy/go-gitlab v0.15.0/go.mod 
h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs=
+github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
+github.com/xdg-go/pbkdf2 v1.0.0/go.mod 
h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
+github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E=
+github.com/xdg-go/scram v1.1.1/go.mod 
h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
+github.com/xdg-go/stringprep v1.0.3 
h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs=
+github.com/xdg-go/stringprep v1.0.3/go.mod 
h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
+github.com/xhit/go-str2duration/v2 v2.1.0 
h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc=
+github.com/xhit/go-str2duration/v2 v2.1.0/go.mod 
h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=
+github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d 
h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
+github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod 
h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
+github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
+github.com/zeebo/xxh3 v1.0.2/go.mod 
h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
+gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b 
h1:7gd+rd8P3bqcn/96gOZa3F5dpJr/vEiDQYlNb/y2uNs=
+gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod 
h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE=
+go.mongodb.org/mongo-driver v1.7.5 
h1:ny3p0reEpgsR2cfA5cjgwFZg3Cv/ofFh/8jbhGtz9VI=
+go.mongodb.org/mongo-driver v1.7.5/go.mod 
h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng=
+go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
+go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc 
v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc 
v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 
h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod 
h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8=
+go.opentelemetry.io/otel v1.29.0 
h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw=
+go.opentelemetry.io/otel v1.29.0/go.mod 
h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 
h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod 
h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI=
+go.opentelemetry.io/otel/metric v1.29.0 
h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc=
+go.opentelemetry.io/otel/metric v1.29.0/go.mod 
h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8=
+go.opentelemetry.io/otel/sdk v1.29.0 
h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo=
+go.opentelemetry.io/otel/sdk v1.29.0/go.mod 
h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok=
+go.opentelemetry.io/otel/trace v1.29.0 
h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4=
+go.opentelemetry.io/otel/trace v1.29.0/go.mod 
h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ=
+go.opentelemetry.io/proto/otlp v1.3.1 
h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
+go.opentelemetry.io/proto/otlp v1.3.1/go.mod 
h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
+go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
+go.uber.org/atomic v1.7.0/go.mod 
h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
+golang.org/x/crypto v0.27.0/go.mod 
h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
+golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 
h1:pVgRXcIictcr+lBQIFeiwuwtDIs4eL21OuM9nyAADmo=
+golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0/go.mod 
h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
+golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
+golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
+golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
+golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
+golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
+golang.org/x/oauth2 v0.21.0/go.mod 
h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
+golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
+golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
+golang.org/x/term v0.24.0/go.mod 
h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
+golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
+golang.org/x/text v0.18.0/go.mod 
h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
+golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
+golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
+golang.org/x/tools v0.24.0/go.mod 
h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
+golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 
h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
+golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod 
h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
+google.golang.org/api v0.169.0 h1:QwWPy71FgMWqJN/l6jVlFHUa29a7dcUy02I8o799nPY=
+google.golang.org/api v0.169.0/go.mod 
h1:gpNOiMA2tZ4mf5R9Iwf4rK/Dcz0fbdIgWYWVoxmsyLg=
+google.golang.org/appengine v1.6.8 
h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
+google.golang.org/appengine v1.6.8/go.mod 
h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
+google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 
h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y=
+google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod 
h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s=
+google.golang.org/genproto/googleapis/api v0.0.0-20240513163218-0867130af1f8 
h1:W5Xj/70xIA4x60O/IFyXivR5MGqblAb8R3w26pnD6No=
+google.golang.org/genproto/googleapis/api 
v0.0.0-20240513163218-0867130af1f8/go.mod 
h1:vPrPUTsDCYxXWjP7clS81mZ6/803D8K4iM9Ma27VKas=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8 
h1:mxSlqyb8ZAHsYDCfiXN1EDdNTdvjUJSLY+OnAUtYNYA=
+google.golang.org/genproto/googleapis/rpc 
v0.0.0-20240513163218-0867130af1f8/go.mod 
h1:I7Y+G38R2bu5j1aLzfFmQfTcU/WnFuqDwLZAbvKTKpM=
+google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA=
+google.golang.org/grpc v1.64.1/go.mod 
h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0=
+google.golang.org/protobuf v1.36.4 
h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM=
+google.golang.org/protobuf v1.36.4/go.mod 
h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod 
h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c 
h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod 
h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
+gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI=
+lukechampine.com/uint128 v1.2.0/go.mod 
h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
+modernc.org/b v1.0.0 h1:vpvqeyp17ddcQWF29Czawql4lDdABCDRbXRAS4+aF2o=
+modernc.org/b v1.0.0/go.mod h1:uZWcZfRj1BpYzfN9JTerzlNUnnPsV9O2ZA8JsRcubNg=
+modernc.org/cc/v3 v3.36.3 h1:uISP3F66UlixxWEcKuIWERa4TwrZENHSL8tWxZz8bHg=
+modernc.org/cc/v3 v3.36.3/go.mod 
h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
+modernc.org/ccgo/v3 v3.16.9 h1:AXquSwg7GuMk11pIdw7fmO1Y/ybgazVkMhsZWCV0mHM=
+modernc.org/ccgo/v3 v3.16.9/go.mod 
h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo=
+modernc.org/db v1.0.0 h1:2c6NdCfaLnshSvY7OU09cyAY0gYXUZj4lmg5ItHyucg=
+modernc.org/db v1.0.0/go.mod h1:kYD/cO29L/29RM0hXYl4i3+Q5VojL31kTUVpVJDw0s8=
+modernc.org/file v1.0.0 h1:9/PdvjVxd5+LcWUQIfapAWRGOkDLK90rloa8s/au06A=
+modernc.org/file v1.0.0/go.mod h1:uqEokAEn1u6e+J45e54dsEA/pw4o7zLrA2GwyntZzjw=
+modernc.org/fileutil v1.0.0 h1:Z1AFLZwl6BO8A5NldQg/xTSjGLetp+1Ubvl4alfGx8w=
+modernc.org/fileutil v1.0.0/go.mod 
h1:JHsWpkrk/CnVV1H/eGlFf85BEpfkrp56ro8nojIq9Q8=
+modernc.org/golex v1.0.0 h1:wWpDlbK8ejRfSyi0frMyhilD3JBvtcx2AdGDnU+JtsE=
+modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
+modernc.org/internal v1.0.0 h1:XMDsFDcBDsibbBnHB2xzljZ+B1yrOVLEFkKL2u15Glw=
+modernc.org/internal v1.0.0/go.mod 
h1:VUD/+JAkhCpvkUitlEOnhpVxCgsBI90oTzSCRcqQVSM=
+modernc.org/libc v1.17.1 h1:Q8/Cpi36V/QBfuQaFVeisEBs3WqoGAJprZzmf7TfEYI=
+modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s=
+modernc.org/lldb v1.0.0 h1:6vjDJxQEfhlOLwl4bhpwIz00uyFK4EmSYcbwqwbynsc=
+modernc.org/lldb v1.0.0/go.mod h1:jcRvJGWfCGodDZz8BPwiKMJxGJngQ/5DrRapkQnLob8=
+modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
+modernc.org/mathutil v1.5.0/go.mod 
h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
+modernc.org/memory v1.2.1 h1:dkRh86wgmq/bJu2cAS2oqBCz/KsMZU7TUM4CibQ7eBs=
+modernc.org/memory v1.2.1/go.mod 
h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
+modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
+modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
+modernc.org/ql v1.0.0 h1:bIQ/trWNVjQPlinI6jdOQsi195SIturGo3mp5hsDqVU=
+modernc.org/ql v1.0.0/go.mod h1:xGVyrLIatPcO2C1JvI/Co8c0sr6y91HKFNy4pt9JXEY=
+modernc.org/sortutil v1.1.0 h1:oP3U4uM+NT/qBQcbg/K2iqAX0Nx7B1b6YZtq3Gk/PjM=
+modernc.org/sortutil v1.1.0/go.mod 
h1:ZyL98OQHJgH9IEfN71VsamvJgrtRX9Dj2gX+vH86L1k=
+modernc.org/sqlite v1.18.1 h1:ko32eKt3jf7eqIkCgPAeHMBXw3riNSLhl2f3loEF7o8=
+modernc.org/sqlite v1.18.1/go.mod 
h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4=
+modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY=
+modernc.org/strutil v1.1.3/go.mod 
h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
+modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk=
+modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
+modernc.org/zappy v1.0.0 h1:dPVaP+3ueIUv4guk8PuZ2wiUGcJ1WUVvIheeSSTD0yk=
+modernc.org/zappy v1.0.0/go.mod h1:hHe+oGahLVII/aTTyWK/b53VDHMAGCBYYeZ9sn83HC4=


Reply via email to