Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions db/TemplateVault.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package db

import (
"errors"

log "github.com/sirupsen/logrus"
)

type TemplateVaultType string

const (
Expand All @@ -19,11 +25,31 @@ type TemplateVault struct {
Vault *AccessKey `db:"-" json:"-"`
}

// FillTemplateVault populates the Vault field of a TemplateVault by fetching
// the associated access key from the database.
//
// If the vault type is TemplateVaultPassword and a VaultKeyID is set, this function
// attempts to retrieve the corresponding AccessKey. If the key is not found
// (returns ErrNotFound), a warning is logged and the function returns successfully
// with the Vault field remaining nil. This allows templates to load even when
// vault keys have been deleted.
//
// For other types of errors, the error is returned to the caller.
func FillTemplateVault(d Store, projectID int, templateVault *TemplateVault) (err error) {
if templateVault.Type == TemplateVaultPassword && templateVault.VaultKeyID != nil {
var vault AccessKey
vault, err = d.GetAccessKey(projectID, *templateVault.VaultKeyID)
if err != nil {
// If the vault key is not found, log a warning but don't fail the entire request.
// This allows templates to load even when vault keys have been deleted.
if errors.Is(err, ErrNotFound) {
log.WithFields(log.Fields{
"vault_id": templateVault.ID,
"vault_key_id": *templateVault.VaultKeyID,
"project_id": projectID,
}).Warn("Template vault references non-existent access key")
return nil
}
return
}
templateVault.Vault = &vault
Expand Down
48 changes: 48 additions & 0 deletions db/bolt/template_vault_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,51 @@ func TestUpdateTemplateVaults(t *testing.T) {
t.Fatalf("expected 1 vault with type 'script', got %d", len(vaults))
}
}

func TestGetTemplateVaults_WithMissingAccessKey(t *testing.T) {
store := CreateTestStore()

proj, err := store.CreateProject(db.Project{
Created: tz.Now(),
Name: "TestProject",
})
if err != nil {
t.Fatal(err.Error())
}

template, err := store.CreateTemplate(db.Template{
ProjectID: proj.ID,
Name: "TestTemplate",
Playbook: "test.yml",
})
if err != nil {
t.Fatal(err.Error())
}

// Create a vault that references a non-existent access key
nonExistentKeyID := 9999
_, err = store.CreateTemplateVault(db.TemplateVault{
ProjectID: proj.ID,
TemplateID: template.ID,
VaultKeyID: &nonExistentKeyID,
Type: "password",
})
if err != nil {
t.Fatal(err.Error())
}

// This should not fail even though the vault key doesn't exist
vaults, err := store.GetTemplateVaults(proj.ID, template.ID)
if err != nil {
t.Fatalf("GetTemplateVaults should not fail when vault key is missing, got error: %v", err)
}

if len(vaults) != 1 {
t.Fatalf("expected 1 vault, got %d", len(vaults))
}

// The vault should be returned but without the Vault field populated
if vaults[0].Vault != nil {
t.Fatal("expected Vault field to be nil when access key is missing")
}
}
37 changes: 37 additions & 0 deletions pro/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,51 @@ go 1.24.2
require github.com/semaphoreui/semaphore v0.0.0-20250712180151-72836311c5b9

require (
dario.cat/mergo v1.0.1 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
github.com/Masterminds/squirrel v1.5.4 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/ProtonMail/go-crypto v1.1.6 // indirect
github.com/cloudflare/circl v1.6.1 // indirect
github.com/creack/pty v1.1.24 // indirect
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-git/go-billy/v5 v5.6.2 // indirect
github.com/go-git/go-git/v5 v5.16.3 // indirect
github.com/go-gorp/gorp/v3 v3.1.0 // indirect
github.com/go-sql-driver/mysql v1.9.3 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/google/go-github v17.0.0+incompatible // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/mux v1.8.1 // indirect
github.com/gorilla/securecookie v1.1.2 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
github.com/lib/pq v1.10.9 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/pjbgf/sha1cd v0.3.2 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/skeema/knownhosts v1.3.1 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
golang.org/x/crypto v0.38.0 // indirect
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
golang.org/x/net v0.39.0 // indirect
golang.org/x/sys v0.33.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
modernc.org/libc v1.65.10 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect
modernc.org/sqlite v1.38.0 // indirect
)

replace github.com/semaphoreui/semaphore => ../
Loading
Loading