sign: wrap signing from stdin

This commit is contained in:
Ophestra 2025-07-19 22:58:26 +09:00
parent 799fe0a610
commit cb39dc5fcf
Signed by: cat
SSH Key Fingerprint: SHA256:gQ67O0enBZ7UdZypgtspB2FDM1g3GVw8nX0XSdcFw8Q
4 changed files with 125 additions and 13 deletions

View File

@ -12,7 +12,7 @@ import (
"slices"
"syscall"
"git.gensokyo.uk/yonah/nixbuild"
"gensokyo.uk/nix"
"hakurei.app/command"
)
@ -21,7 +21,7 @@ type commandHandlerError string
func (c commandHandlerError) Error() string { return string(c) }
func main() {
var ctx nixbuild.Context
var ctx nix.Context
nixCtx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
@ -39,7 +39,7 @@ func main() {
if flagVerbose {
stderr = os.Stderr
}
ctx = nixbuild.New(nixCtx, nil, os.Stdout, stderr)
ctx = nix.New(nixCtx, nil, os.Stdout, stderr)
return nil
}).
@ -52,7 +52,7 @@ func main() {
return commandHandlerError("show requires at least 1 argument")
}
if drv, err := nixbuild.DerivationShow(ctx, slices.Values(args)); err != nil {
if drv, err := nix.DerivationShow(ctx, slices.Values(args)); err != nil {
return commandHandlerError(fmt.Sprintf("cannot show: %v", err))
} else {
log.Printf("got %d derivations:\n%#v", len(drv), drv)
@ -65,12 +65,27 @@ func main() {
return commandHandlerError("build requires at least 1 argument")
}
if err := nixbuild.Build(ctx, slices.Values(args)); err != nil {
if err := nix.Build(ctx, slices.Values(args)); err != nil {
return commandHandlerError(fmt.Sprintf("cannot build: %v", err))
}
return nil
})
var (
flagSignKey string
)
c.NewCommand("sign", command.UsageInternal, func(args []string) error {
if len(args) < 1 {
return commandHandlerError("sign requires at least 1 argument")
}
if err := nix.Sign(ctx, flagSignKey, slices.Values(args)); err != nil {
return commandHandlerError(fmt.Sprintf("cannot sign: %v", err))
}
return nil
}).
Flag(&flagSignKey, "key", command.StringFlag("/var/lib/persist/cache/key"), "File containing the secret signing key")
var (
resolveFlagOut string
)
@ -82,23 +97,23 @@ func main() {
log.Printf("evaluating %s", installable)
var installables []string
if v, err := nixbuild.EvalInstantiated(ctx, installable); err != nil {
if v, err := nix.EvalInstantiated(ctx, installable); err != nil {
return commandHandlerError(fmt.Sprintf("cannot evaluate for instantiated derivations: %v", err))
} else {
installables = v
}
log.Println("building instantiated derivations")
if err := nixbuild.Build(ctx, slices.Values(installables)); err != nil {
if err := nix.Build(ctx, slices.Values(installables)); err != nil {
return commandHandlerError(fmt.Sprintf("cannot build: %v", err))
}
var collective []string
log.Println("collecting store paths")
if derivations, err := nixbuild.DerivationShow(ctx, slices.Values(installables)); err != nil {
if derivations, err := nix.DerivationShow(ctx, slices.Values(installables)); err != nil {
return commandHandlerError(fmt.Sprintf("cannot show: %v", err))
} else {
collective = nixbuild.CollectFromDerivations(derivations)
collective = nix.CollectFromDerivations(derivations)
}
f, err := os.Create(resolveFlagOut)
@ -110,7 +125,7 @@ func main() {
return commandHandlerError(fmt.Sprintf("cannot serialise JSON: %v", err))
}
} else {
if _, err = nixbuild.WriteStdin(f, slices.Values(collective)); err != nil {
if _, err = nix.WriteStdin(f, slices.Values(collective)); err != nil {
return commandHandlerError(fmt.Sprintf("cannot write store path list: %v", err))
}
}
@ -126,7 +141,7 @@ func main() {
log.Println("initialising evaluator")
var collective []string
if eval, err := nixbuild.NewInstantiatedEvaluator(ctx, installable); err != nil {
if eval, err := nix.NewInstantiatedEvaluator(ctx, installable); err != nil {
return commandHandlerError(fmt.Sprintf("cannot initialise evaluator: %v", err))
} else {
log.Println("collecting paths")
@ -150,7 +165,7 @@ func main() {
return err
}
if v, err := nixbuild.EvalInstantiated(ctx, installable); err != nil {
if v, err := nix.EvalInstantiated(ctx, installable); err != nil {
return commandHandlerError(fmt.Sprintf("cannot evaluate for instantiated derivations: %v", err))
} else if flagJSON {
if err = json.NewEncoder(os.Stdout).Encode(v); err != nil {
@ -158,7 +173,7 @@ func main() {
}
return nil
} else {
_, _ = nixbuild.WriteStdin(os.Stdout, slices.Values(v))
_, _ = nix.WriteStdin(os.Stdout, slices.Values(v))
return nil
}
})

View File

@ -17,6 +17,25 @@ const (
CommandDerivationAdd = "add"
// CommandDerivationShow show the contents of a store derivation
CommandDerivationShow = "show"
// CommandStore manipulate a Nix store.
CommandStore = "store"
// CommandStoreSign sign store paths with a local key
CommandStoreSign = "sign"
// FlagAll apply the operation to every store path.
FlagAll = "--all"
// FlagDerivation operate on the store derivation rather than its outputs.
FlagDerivation = "--derivation"
// FlagExpr interpret installables as attribute paths relative to the Nix expression expr.
FlagExpr = "--expr"
// FlagFile interpret installables as attribute paths relative to the Nix expression stored in file.
// If file is the character -, then a Nix expression will be read from standard input. Implies --impure.
FlagFile = "--file"
// FlagRecursive apply operation to closure of the specified paths.
FlagRecursive = "--recursive"
// FlagKeyFile file containing the secret signing key.
FlagKeyFile = "--key-file"
// FlagDryRun show what this command would do without doing it.
FlagDryRun = "--dry-run"

23
sign.go Normal file
View File

@ -0,0 +1,23 @@
package nix
import (
"context"
"iter"
)
// Sign recursively signs installables using the key at keyPath.
func Sign(ctx Context, keyPath string, installables iter.Seq[string]) error {
c, cancel := context.WithCancel(ctx.Unwrap())
defer cancel()
cmd := ctx.Nix(c, CommandStore, CommandStoreSign,
FlagPrintBuildLogs, FlagVerbose,
// this is quite useless if not signing recursively
FlagRecursive,
FlagKeyFile, keyPath,
FlagStdin)
cmd.Stdout, cmd.Stderr = ctx.Streams()
_, err := ctx.WriteStdin(cmd, installables, nil)
return err
}

55
sign_test.go Normal file
View File

@ -0,0 +1,55 @@
package nix_test
import (
"os"
"slices"
"syscall"
"testing"
"gensokyo.uk/nix"
"hakurei.app/command"
)
func init() {
stubCommandInit = append(stubCommandInit, func(c command.Command) {
commandStore := c.New(nix.CommandStore, "emit samples for various `nix store` cases")
var (
flagSignPBL bool
flagSignVerbose bool
flagSignRecursive bool
flagSignKeyFile string
flagSignStdin bool
)
commandStore.NewCommand(nix.CommandStoreSign, "emit samples for various `nix store sign` cases", func(args []string) error {
if !flagSignPBL || !flagSignVerbose || !flagSignRecursive || flagSignKeyFile != "/proc/nonexistent" {
return syscall.ENOSYS
}
installables, err := nix.ReadStdin(os.Stdin)
if err != nil {
return err
}
if !slices.Equal(installables, instWant["pluiedev pappardelle"]) {
return syscall.EINVAL
}
return nil
}).
Flag(&flagSignPBL, trimFlagName(nix.FlagPrintBuildLogs), command.BoolFlag(false), nix.FlagPrintBuildLogs).
Flag(&flagSignVerbose, trimFlagName(nix.FlagVerbose), command.BoolFlag(false), nix.FlagVerbose).
Flag(&flagSignRecursive, trimFlagName(nix.FlagRecursive), command.BoolFlag(false), nix.FlagRecursive).
Flag(&flagSignKeyFile, trimFlagName(nix.FlagKeyFile), command.StringFlag(""), nix.FlagKeyFile).
Flag(&flagSignStdin, trimFlagName(nix.FlagStdin), command.BoolFlag(false), nix.FlagStdin)
})
}
func TestSign(t *testing.T) {
stubNixCommand(t)
if err := nix.Sign(
newStubContext(t.Context(), nil, os.Stdout, os.Stderr),
"/proc/nonexistent",
slices.Values(instWant["pluiedev pappardelle"]),
); err != nil {
t.Errorf("Sign: error = %v", err)
}
}