diff options
author | Sami Hiltunen <shiltunen@gitlab.com> | 2023-05-21 12:57:58 +0300 |
---|---|---|
committer | Sami Hiltunen <shiltunen@gitlab.com> | 2023-05-25 17:57:47 +0300 |
commit | aa673104814904ac6dc0986a53cfc519466e06e0 (patch) | |
tree | ec0f032fdf7dd91616e2c9bb594dbe4c0fedac8e /internal/gitaly/transaction_manager.go | |
parent | e9a888be7035afa5d5854110801cdb42b1411e3f (diff) |
Validate custom hook archive prior to accepting a transaction
TransactionManager is currently not validating the custom hook archive
in any way prior to accepting and logging the transaction. This could
lead to invalid hook archive being logged which would prevent applying
the log entry of the transaction leading to transaction processing halting.
This commit verifies the archive by extracting it on the disk to the
staging directory prior to logging. These extracted files can then later
be also used for computing a vote to Praefect from the hook files. For
now, no other validation is performed than just ensuring the hooks can
be extracted on the disk. This matches the behavior in SetCustomHooks
which also doesn't verify anything. This is something we should improve
later. However, if the hooks extract successfully, the log processing won't
fail because of them. If the hooks fail to execute, it will fail the
hook execution but that's outside of the scope of the TransactionManager.
The hooks can still be fixed by committing new ones.
Diffstat (limited to 'internal/gitaly/transaction_manager.go')
-rw-r--r-- | internal/gitaly/transaction_manager.go | 28 |
1 files changed, 28 insertions, 0 deletions
diff --git a/internal/gitaly/transaction_manager.go b/internal/gitaly/transaction_manager.go index 5862cd5d2..629ec9da2 100644 --- a/internal/gitaly/transaction_manager.go +++ b/internal/gitaly/transaction_manager.go @@ -521,6 +521,10 @@ func (mgr *TransactionManager) commit(ctx context.Context, transaction *Transact return fmt.Errorf("setup staging repository: %w", err) } + if err := mgr.stageHooks(ctx, transaction); err != nil { + return fmt.Errorf("stage hooks: %w", err) + } + if err := mgr.packObjects(ctx, transaction); err != nil { return fmt.Errorf("pack objects: %w", err) } @@ -544,6 +548,30 @@ func (mgr *TransactionManager) commit(ctx context.Context, transaction *Transact } } +// stageHooks extracts the new hooks, if any, into <stagingDirectory>/custom_hooks. This is ensures the TAR +// is valid prior to committing the transaction. The hooks files on the disk are also used to compute a vote +// for Praefect. +func (mgr *TransactionManager) stageHooks(ctx context.Context, transaction *Transaction) error { + if transaction.customHooksUpdate == nil || len(transaction.customHooksUpdate.CustomHooksTAR) == 0 { + return nil + } + + if err := transaction.initStagingDirectory(); err != nil { + return fmt.Errorf("init staging directory: %w", err) + } + + if err := repoutil.ExtractHooks( + ctx, + bytes.NewReader(transaction.customHooksUpdate.CustomHooksTAR), + transaction.stagingDirectory, + false, + ); err != nil { + return fmt.Errorf("extract hooks: %w", err) + } + + return nil +} + // setupStagingRepository sets a repository that is used to stage the transaction. The staging repository // has the quarantine applied so the objects are available for packing and verifying the references. func (mgr *TransactionManager) setupStagingRepository(ctx context.Context, transaction *Transaction) error { |