feat: support secure Forgejo password files

This commit is contained in:
eding 2026-09-13 17:23:57 +02:00
parent beca1b5d36
commit 2b545f662f

View file

@ -3,6 +3,7 @@ package cmd
import ( import (
"errors" "errors"
"fmt" "fmt"
"os"
"strings" "strings"
"github.com/Pingu-Studio/MaidnCLI/internal/bootstrap" "github.com/Pingu-Studio/MaidnCLI/internal/bootstrap"
@ -23,6 +24,7 @@ var bootstrapPromptOperationalSecrets bool
var bootstrapInitializeOpenBaoRecovery bool var bootstrapInitializeOpenBaoRecovery bool
var bootstrapInitializeOpenBao bool var bootstrapInitializeOpenBao bool
var bootstrapCreateForgejoRegistryToken bool var bootstrapCreateForgejoRegistryToken bool
var bootstrapForgejoPasswordFile string
var bootstrapCreateForgejoDeliveryStatusToken bool var bootstrapCreateForgejoDeliveryStatusToken bool
var bootstrapProvisionAppSecretIdentities bool var bootstrapProvisionAppSecretIdentities bool
var bootstrapE2EApp string var bootstrapE2EApp string
@ -56,6 +58,7 @@ func init() {
bootstrapCmd.Flags().BoolVar(&bootstrapInitializeOpenBaoRecovery, "initialize-openbao-recovery", false, "Create and save a separate OpenBao recovery age identity for --config") bootstrapCmd.Flags().BoolVar(&bootstrapInitializeOpenBaoRecovery, "initialize-openbao-recovery", false, "Create and save a separate OpenBao recovery age identity for --config")
bootstrapCmd.Flags().BoolVar(&bootstrapInitializeOpenBao, "initialize-openbao", false, "Initialize OpenBao and seed encrypted operational secrets for --config") bootstrapCmd.Flags().BoolVar(&bootstrapInitializeOpenBao, "initialize-openbao", false, "Initialize OpenBao and seed encrypted operational secrets for --config")
bootstrapCmd.Flags().BoolVar(&bootstrapCreateForgejoRegistryToken, "create-forgejo-registry-token", false, "Create a least-privilege Forgejo package registry token and seed it through OpenBao") bootstrapCmd.Flags().BoolVar(&bootstrapCreateForgejoRegistryToken, "create-forgejo-registry-token", false, "Create a least-privilege Forgejo package registry token and seed it through OpenBao")
bootstrapCmd.Flags().StringVar(&bootstrapForgejoPasswordFile, "forgejo-password-file", "", "Read the Forgejo password from this local file when creating a registry token")
bootstrapCmd.Flags().BoolVar(&bootstrapCreateForgejoDeliveryStatusToken, "create-forgejo-delivery-status-token", false, "Create or reuse the Forgejo delivery-status token and seed it through OpenBao") bootstrapCmd.Flags().BoolVar(&bootstrapCreateForgejoDeliveryStatusToken, "create-forgejo-delivery-status-token", false, "Create or reuse the Forgejo delivery-status token and seed it through OpenBao")
bootstrapCmd.Flags().BoolVar(&bootstrapProvisionAppSecretIdentities, "provision-app-secret-identities", false, "Create restricted app-secret and E2E OpenBao identities") bootstrapCmd.Flags().BoolVar(&bootstrapProvisionAppSecretIdentities, "provision-app-secret-identities", false, "Create restricted app-secret and E2E OpenBao identities")
bootstrapCmd.Flags().StringVar(&bootstrapE2EApp, "e2e-app", "", "Fixture app granted an E2E probe identity") bootstrapCmd.Flags().StringVar(&bootstrapE2EApp, "e2e-app", "", "Fixture app granted an E2E probe identity")
@ -261,7 +264,7 @@ func createForgejoRegistryToken(cfg config.Config) error {
if _, err := bootstrap.ReadOperationalSecrets(cfg.SOPS.OperationalSecretsPath, cfg.SOPS.AgeKeyPath); err != nil { if _, err := bootstrap.ReadOperationalSecrets(cfg.SOPS.OperationalSecretsPath, cfg.SOPS.AgeKeyPath); err != nil {
return err return err
} }
password, otp, name, err := ui.PromptForgejoRegistryToken() password, otp, name, err := forgejoRegistryTokenCredentials()
if err != nil { if err != nil {
return err return err
} }
@ -282,6 +285,21 @@ func createForgejoRegistryToken(cfg config.Config) error {
return nil return nil
} }
func forgejoRegistryTokenCredentials() (password, otp, name string, err error) {
if bootstrapForgejoPasswordFile == "" {
return ui.PromptForgejoRegistryToken()
}
data, err := os.ReadFile(bootstrapForgejoPasswordFile)
if err != nil {
return "", "", "", fmt.Errorf("read Forgejo password file: %w", err)
}
password = strings.TrimSpace(string(data))
if password == "" {
return "", "", "", errors.New("Forgejo password file is empty")
}
return password, "", "maidn-registry", nil
}
func createOrReuseForgejoDeliveryStatusToken(cfg config.Config) error { func createOrReuseForgejoDeliveryStatusToken(cfg config.Config) error {
secrets, err := readOperationalSecrets(cfg.SOPS.OperationalSecretsPath, cfg.SOPS.AgeKeyPath) secrets, err := readOperationalSecrets(cfg.SOPS.OperationalSecretsPath, cfg.SOPS.AgeKeyPath)
if err != nil { if err != nil {