Reject ssh-signing-reuse early in github and gitea
`bootstrap github` and `bootstrap gitea` generate the SSH transport key in-process, so they have no operator-supplied key to reuse for commit signing. Both subcommands already reject `--ssh-signing-reuse-private-key` with a provider-specific "not supported" error, but the check sat after `bootstrapValidate`, which fails first with the generic "--ssh-signing-reuse-private-key requires --private-key-file" message. A user invoking e.g. `flux bootstrap github --ssh-signing-reuse-private-key` is told to set a flag that the subcommand cannot honour anyway, masking the real problem. Move the unsupported-flag rejection to the top of each `RunE` — before the interactive PAT prompt and before `bootstrapValidate` — so the provider-specific error wins. The deeper, now-redundant check is dropped. `TestBootstrapProviderRejectsReuseBeforeValidate` exercises both subcommands with the reuse flag set and no `--private-key-file` to lock in the precedence. Assisted-by: claude/opus-4.7 Signed-off-by: Hidde Beydals <hidde@hhh.computer>
This commit is contained in:
@@ -107,6 +107,11 @@ func init() {
|
||||
}
|
||||
|
||||
func bootstrapGiteaCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if bootstrapArgs.sshSigningReusePrivateKey {
|
||||
return fmt.Errorf("--ssh-signing-reuse-private-key is not supported by 'bootstrap gitea'; " +
|
||||
"that subcommand generates the SSH transport key in-process and has no operator-supplied key to reuse")
|
||||
}
|
||||
|
||||
gtToken := os.Getenv(gtTokenEnvVar)
|
||||
if gtToken == "" {
|
||||
var err error
|
||||
@@ -254,11 +259,6 @@ func bootstrapGiteaCmdRun(cmd *cobra.Command, args []string) error {
|
||||
bootstrap.WithGitCommitSigning(entityList, bootstrapArgs.gpgPassphrase, bootstrapArgs.gpgKeyID),
|
||||
}
|
||||
|
||||
if bootstrapArgs.sshSigningReusePrivateKey {
|
||||
return fmt.Errorf("--ssh-signing-reuse-private-key is not supported by 'bootstrap gitea'; " +
|
||||
"that subcommand generates the SSH transport key in-process and has no operator-supplied key to reuse")
|
||||
}
|
||||
|
||||
if bootstrapArgs.sshHostname != "" {
|
||||
bootstrapOpts = append(bootstrapOpts, bootstrap.WithSSHHostname(bootstrapArgs.sshHostname))
|
||||
}
|
||||
|
||||
@@ -107,6 +107,11 @@ func init() {
|
||||
}
|
||||
|
||||
func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if bootstrapArgs.sshSigningReusePrivateKey {
|
||||
return fmt.Errorf("--ssh-signing-reuse-private-key is not supported by 'bootstrap github'; " +
|
||||
"that subcommand generates the SSH transport key in-process and has no operator-supplied key to reuse")
|
||||
}
|
||||
|
||||
ghToken := os.Getenv(ghTokenEnvVar)
|
||||
if ghToken == "" {
|
||||
var err error
|
||||
@@ -261,11 +266,6 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
|
||||
bootstrap.WithGitCommitSigning(entityList, bootstrapArgs.gpgPassphrase, bootstrapArgs.gpgKeyID),
|
||||
}
|
||||
|
||||
if bootstrapArgs.sshSigningReusePrivateKey {
|
||||
return fmt.Errorf("--ssh-signing-reuse-private-key is not supported by 'bootstrap github'; " +
|
||||
"that subcommand generates the SSH transport key in-process and has no operator-supplied key to reuse")
|
||||
}
|
||||
|
||||
if bootstrapArgs.sshHostname != "" {
|
||||
bootstrapOpts = append(bootstrapOpts, bootstrap.WithSSHHostname(bootstrapArgs.sshHostname))
|
||||
}
|
||||
|
||||
@@ -159,3 +159,50 @@ func TestBootstrapValidate_signingFlags(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Providers that generate the SSH transport key in-process (github, gitea)
|
||||
// must reject --ssh-signing-reuse-private-key with their own, provider-
|
||||
// specific error before bootstrapValidate runs — otherwise the generic
|
||||
// "--ssh-signing-reuse-private-key requires --private-key-file" error
|
||||
// shadows the fact that the flag is fundamentally unsupported there.
|
||||
func TestBootstrapProviderRejectsReuseBeforeValidate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
runE func() error
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "github rejects reuse with provider-specific error",
|
||||
runE: func() error { return bootstrapGitHubCmdRun(nil, nil) },
|
||||
wantErr: "not supported by 'bootstrap github'",
|
||||
},
|
||||
{
|
||||
name: "gitea rejects reuse with provider-specific error",
|
||||
runE: func() error { return bootstrapGiteaCmdRun(nil, nil) },
|
||||
wantErr: "not supported by 'bootstrap gitea'",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
savedReuse := bootstrapArgs.sshSigningReusePrivateKey
|
||||
savedPrivKey := bootstrapArgs.privateKeyFile
|
||||
defer func() {
|
||||
bootstrapArgs.sshSigningReusePrivateKey = savedReuse
|
||||
bootstrapArgs.privateKeyFile = savedPrivKey
|
||||
}()
|
||||
|
||||
// Reuse flag set, no --private-key-file: bootstrapValidate
|
||||
// would otherwise return "requires --private-key-file".
|
||||
bootstrapArgs.sshSigningReusePrivateKey = true
|
||||
bootstrapArgs.privateKeyFile = ""
|
||||
|
||||
err := tt.runE()
|
||||
if err == nil {
|
||||
t.Fatalf("expected error containing %q, got nil", tt.wantErr)
|
||||
}
|
||||
if !strings.Contains(err.Error(), tt.wantErr) {
|
||||
t.Fatalf("expected error containing %q, got: %v", tt.wantErr, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user