Recoverable means sealed to the current operator key; recovery names the provider

From review: the export counted any operator-sealed row as recoverable, so a
secret sealed to a replaced key was reported as openable with the current one;
replacing the key counted orphans in one table of two; and a pair credential
held from two providers was recovered as whichever row came first. The export
now lists what the current key opens, what an earlier key opens, and what has
no copy; `secret recover` takes --provider and refuses ambiguity; files that
must not exist are created exclusively; one constructor builds the export for
the operator's file and the vault's disk alike.
This commit is contained in:
2026-09-21 01:16:32 +02:00
parent 565f144a20
commit 77e6c1a684
9 changed files with 308 additions and 141 deletions
+8 -5
View File
@@ -12,18 +12,21 @@ func TestAThirdRecipientOpensWithItsOwnKeyOnly(t *testing.T) {
if err != nil {
t.Fatal(err)
}
sealed, more, err := MakeAlso(nodePub, nodePub, opPub)
sealed, forOperator, err := MakeWithOperator(nodePub, nodePub, opPub)
if err != nil {
t.Fatal(err)
}
if len(more) != 1 {
t.Fatalf("%d extra blobs for one extra key", len(more))
if forOperator == "" {
t.Fatal("no blob for the operator")
}
if _, none, err := MakeWithOperator(nodePub, nodePub, ""); err != nil || none != "" {
t.Fatalf("no operator key, yet a blob %q (%v)", none, err)
}
fromNode, err := Open(nodePriv, sealed.ForConsumer)
if err != nil {
t.Fatal(err)
}
fromOperator, err := Open(opPriv, more[0])
fromOperator, err := Open(opPriv, forOperator)
if err != nil {
t.Fatal(err)
}
@@ -33,7 +36,7 @@ func TestAThirdRecipientOpensWithItsOwnKeyOnly(t *testing.T) {
if len(fromNode) != 40 {
t.Fatalf("a minted value is %d characters, not 40", len(fromNode))
}
if _, err := Open(nodePriv, more[0]); err == nil {
if _, err := Open(nodePriv, forOperator); err == nil {
t.Fatal("the node's key opened the operator's blob")
}
if _, err := Open(opPriv, sealed.ForConsumer); err == nil {