feat: harden platform operations #6

Merged
eding merged 5 commits from feat/ops-and-delivery-hardening into main 2026-08-02 02:45:14 +02:00
2 changed files with 66 additions and 1 deletions
Showing only changes of commit 3e1ce9f62c - Show all commits

View file

@ -27,6 +27,8 @@ var bootstrapPublishAppFrom string
var bootstrapMergeBootstrapPR bool
var bootstrapManageNetworkBridges bool
var upsertOperationalSecret = bootstrap.UpsertOperationalSecret
var bootstrapCmd = &cobra.Command{
Use: "bootstrap",
Short: "Bootstrap Talos and Flux from config or an interactive wizard.",
@ -216,11 +218,26 @@ func runBootstrap(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
if bootstrapRegisterWebhook {
if err := seedForgejoOperationalCredentials(cfg); err != nil {
return err
}
}
runner := bootstrap.Runner{Config: cfg, Mode: bootstrap.Mode(bootstrapMode), ConfirmRebuild: bootstrapYes, RegisterWebhook: bootstrapRegisterWebhook}
return runner.Run()
}
func seedForgejoOperationalCredentials(cfg config.Config) error {
if err := upsertOperationalSecret(cfg.SOPS.OperationalSecretsPath, cfg.SOPS.AgeKeyPath, "cicd/forgejo", "username", cfg.Git.Username); err != nil {
return fmt.Errorf("save Forgejo username for webhook registration: %w", err)
}
if err := upsertOperationalSecret(cfg.SOPS.OperationalSecretsPath, cfg.SOPS.AgeKeyPath, "cicd/forgejo", "token", cfg.Git.Token); err != nil {
return fmt.Errorf("save Forgejo token for webhook registration: %w", err)
}
return nil
}
func createForgejoRegistryToken(cfg config.Config) error {
if _, err := bootstrap.ReadOperationalSecrets(cfg.SOPS.OperationalSecretsPath, cfg.SOPS.AgeKeyPath); err != nil {
return err

View file

@ -1,6 +1,12 @@
package cmd
import "testing"
import (
"errors"
"strings"
"testing"
"github.com/Pingu-Studio/MaidnCLI/internal/config"
)
func TestCreateForgejoRegistryTokenRequiresConfig(t *testing.T) {
originalConfigPath, originalCreate := bootstrapConfigPath, bootstrapCreateForgejoRegistryToken
@ -14,3 +20,45 @@ func TestCreateForgejoRegistryTokenRequiresConfig(t *testing.T) {
t.Fatal("--create-forgejo-registry-token accepted a missing --config")
}
}
func TestSeedForgejoOperationalCredentialsUsesEncryptedUpsertBoundary(t *testing.T) {
original := upsertOperationalSecret
t.Cleanup(func() { upsertOperationalSecret = original })
cfg := config.Config{
Git: config.GitConfig{Username: "webhook-bot", Token: "test-pat"},
SOPS: config.SOPSConfig{OperationalSecretsPath: "secrets.sops.yaml", AgeKeyPath: "age-key.txt"},
}
type call struct{ path, key, value string }
var calls []call
upsertOperationalSecret = func(secretsPath, ageKeyPath, path, key, value string) error {
if secretsPath != cfg.SOPS.OperationalSecretsPath || ageKeyPath != cfg.SOPS.AgeKeyPath {
t.Fatal("credential upsert used unexpected secret paths")
}
calls = append(calls, call{path, key, value})
return nil
}
if err := seedForgejoOperationalCredentials(cfg); err != nil {
t.Fatal(err)
}
if len(calls) != 2 || calls[0] != (call{"cicd/forgejo", "username", cfg.Git.Username}) || calls[1] != (call{"cicd/forgejo", "token", cfg.Git.Token}) {
t.Fatal("configured Forgejo credentials were not passed only to the encrypted upsert boundary")
}
}
func TestSeedForgejoOperationalCredentialsHidesTokenOnUpsertFailure(t *testing.T) {
original := upsertOperationalSecret
t.Cleanup(func() { upsertOperationalSecret = original })
cfg := config.Config{Git: config.GitConfig{Username: "webhook-bot", Token: "test-pat"}}
upsertOperationalSecret = func(_, _, _, key, _ string) error {
if key == "token" {
return errors.New("unavailable")
}
return nil
}
err := seedForgejoOperationalCredentials(cfg)
if err == nil || !strings.Contains(err.Error(), "save Forgejo token for webhook registration") || strings.Contains(err.Error(), cfg.Git.Token) {
t.Fatal("credential upsert failure was not clear and token-safe")
}
}