mirror of
https://github.com/lightninglabs/lightning-terminal.git
synced 2026-08-13 12:33:36 +02:00
itest: add test for super macaroon auto-bake
Add testSuperMacaroonOnStartup to verify startup baking logic. The test restarts the node with the auto-baking config flags and asserts the macaroon is baked with read-only or read-write permissions accordingly. Also add validation tests verifying that starting with an invalid path suffix or in stateless-init mode with baking enabled fails as expected. Verify permission addition/expansion by starting the node with sub-servers disabled and then restarting with sub-servers re-enabled. Also verify the none config choice, asserting that no super macaroon file is baked/created on startup.
This commit is contained in:
parent
c5fbbd4d77
commit
7cde9c50ae
2 changed files with 219 additions and 0 deletions
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -1530,3 +1531,217 @@ func bakeSuperMacaroon(t *testing.T, cfg *LitNodeConfig,
|
||||||
|
|
||||||
return tempFile.Name()
|
return tempFile.Name()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// testSuperMacaroonOnStartup tests that the super macaroon is successfully
|
||||||
|
// baked on startup if configured.
|
||||||
|
func testSuperMacaroonOnStartup(ctx context.Context, net *NetworkHarness,
|
||||||
|
t *harnessTest) {
|
||||||
|
|
||||||
|
superMacPath := filepath.Join(
|
||||||
|
net.Alice.Cfg.LitDir, "startup-super.macaroon",
|
||||||
|
)
|
||||||
|
|
||||||
|
verifyMacaroonPermissions := func(path string, expectWrite bool) {
|
||||||
|
ctxTimeout, cancel := context.WithTimeout(ctx, defaultTimeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
rawConn, err := connectRPC(
|
||||||
|
ctxTimeout, net.Alice.Cfg.LitAddr(),
|
||||||
|
net.Alice.Cfg.LitTLSCertPath,
|
||||||
|
)
|
||||||
|
require.NoError(t.t, err)
|
||||||
|
defer rawConn.Close()
|
||||||
|
|
||||||
|
macBytes, err := os.ReadFile(path)
|
||||||
|
require.NoError(t.t, err)
|
||||||
|
|
||||||
|
ctxm := macaroonContext(ctxTimeout, macBytes)
|
||||||
|
lnrpcConn := lnrpc.NewLightningClient(rawConn)
|
||||||
|
|
||||||
|
_, err = lnrpcConn.GetInfo(ctxm, &lnrpc.GetInfoRequest{})
|
||||||
|
require.NoError(t.t, err)
|
||||||
|
|
||||||
|
_, err = lnrpcConn.NewAddress(ctxm, &lnrpc.NewAddressRequest{
|
||||||
|
Type: lnrpc.AddressType_WITNESS_PUBKEY_HASH,
|
||||||
|
})
|
||||||
|
if expectWrite {
|
||||||
|
require.NoError(t.t, err)
|
||||||
|
} else {
|
||||||
|
require.Error(t.t, err)
|
||||||
|
require.Contains(t.t, err.Error(), "permission denied")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
verifyMacaroonSubserverPermissions := func(path string,
|
||||||
|
expectSubservers bool) {
|
||||||
|
|
||||||
|
macBytes, err := os.ReadFile(path)
|
||||||
|
require.NoError(t.t, err)
|
||||||
|
|
||||||
|
mac := &macaroon.Macaroon{}
|
||||||
|
err = mac.UnmarshalBinary(macBytes)
|
||||||
|
require.NoError(t.t, err)
|
||||||
|
|
||||||
|
rawID := mac.Id()
|
||||||
|
require.NotEmpty(t.t, rawID)
|
||||||
|
|
||||||
|
decodedID := &lnrpc.MacaroonId{}
|
||||||
|
err = proto.Unmarshal(rawID[1:], decodedID)
|
||||||
|
require.NoError(t.t, err)
|
||||||
|
|
||||||
|
hasSubserver := false
|
||||||
|
for _, op := range decodedID.Ops {
|
||||||
|
if op == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if op.Entity == "loop" || op.Entity == "pool" ||
|
||||||
|
op.Entity == "faraday" {
|
||||||
|
|
||||||
|
hasSubserver = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if expectSubservers {
|
||||||
|
require.True(
|
||||||
|
t.t, hasSubserver,
|
||||||
|
"expected macaroon to contain "+
|
||||||
|
"subserver permissions",
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
require.False(
|
||||||
|
t.t, hasSubserver,
|
||||||
|
"expected macaroon NOT to contain "+
|
||||||
|
"subserver permissions",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure any old file is removed first.
|
||||||
|
_ = os.Remove(superMacPath)
|
||||||
|
|
||||||
|
// Test that starting Alice with an invalid super-macaroon-path (not
|
||||||
|
// ending with .macaroon) fails.
|
||||||
|
invalidMacPath := filepath.Join(
|
||||||
|
net.Alice.Cfg.LitDir, "invalid-path.mac",
|
||||||
|
)
|
||||||
|
err := net.RestartNode(
|
||||||
|
net.Alice, nil, []LitArgOption{
|
||||||
|
WithLitArg("bake-super-macaroon", "read-only"),
|
||||||
|
WithLitArg("super-macaroon-path", invalidMacPath),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
require.Error(t.t, err)
|
||||||
|
|
||||||
|
// Drain the expected process exit error from the error channel to
|
||||||
|
// prevent it from failing the test runner at the end of the test.
|
||||||
|
select {
|
||||||
|
case <-net.lndErrorChan:
|
||||||
|
case <-time.After(defaultTimeout):
|
||||||
|
t.t.Fatalf("expected process exit error in lndErrorChan")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restart Alice with read-only super macaroon baking enabled.
|
||||||
|
err = net.RestartNode(
|
||||||
|
net.Alice, nil, []LitArgOption{
|
||||||
|
WithLitArg("bake-super-macaroon", "read-only"),
|
||||||
|
WithLitArg("super-macaroon-path", superMacPath),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
require.NoError(t.t, err)
|
||||||
|
|
||||||
|
// Verify that the super macaroon was created on startup.
|
||||||
|
require.FileExists(t.t, superMacPath)
|
||||||
|
|
||||||
|
// Verify permissions: write should be blocked.
|
||||||
|
verifyMacaroonPermissions(superMacPath, false)
|
||||||
|
|
||||||
|
// Restart Alice with a read-write super macaroon, WITHOUT
|
||||||
|
// deleting the file. This will test the overwrite behavior when
|
||||||
|
// permissions differ.
|
||||||
|
err = net.RestartNode(
|
||||||
|
net.Alice, nil, []LitArgOption{
|
||||||
|
WithLitArg("bake-super-macaroon", "read-write"),
|
||||||
|
WithLitArg("super-macaroon-path", superMacPath),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
require.NoError(t.t, err)
|
||||||
|
|
||||||
|
require.FileExists(t.t, superMacPath)
|
||||||
|
|
||||||
|
// Verify permissions: write should succeed.
|
||||||
|
verifyMacaroonPermissions(superMacPath, true)
|
||||||
|
|
||||||
|
// Restart Alice back with a read-only super macaroon, WITHOUT
|
||||||
|
// deleting the file. This will test the overwrite behavior when
|
||||||
|
// switching back to read-only.
|
||||||
|
err = net.RestartNode(
|
||||||
|
net.Alice, nil, []LitArgOption{
|
||||||
|
WithLitArg("bake-super-macaroon", "read-only"),
|
||||||
|
WithLitArg("super-macaroon-path", superMacPath),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
require.NoError(t.t, err)
|
||||||
|
|
||||||
|
require.FileExists(t.t, superMacPath)
|
||||||
|
|
||||||
|
// Verify permissions: write should be blocked again.
|
||||||
|
verifyMacaroonPermissions(superMacPath, false)
|
||||||
|
|
||||||
|
// Restart Alice with a sub-server disabled to bake a super macaroon
|
||||||
|
// with a subset of permissions.
|
||||||
|
err = net.RestartNode(
|
||||||
|
net.Alice, nil, []LitArgOption{
|
||||||
|
WithLitArg("bake-super-macaroon", "read-write"),
|
||||||
|
WithLitArg("super-macaroon-path", superMacPath),
|
||||||
|
WithLitArg("loop-mode", "disable"),
|
||||||
|
WithLitArg("pool-mode", "disable"),
|
||||||
|
WithLitArg("faraday-mode", "disable"),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
require.NoError(t.t, err)
|
||||||
|
|
||||||
|
require.FileExists(t.t, superMacPath)
|
||||||
|
verifyMacaroonSubserverPermissions(superMacPath, false)
|
||||||
|
|
||||||
|
// Restart Alice with the sub-servers re-enabled. This will add
|
||||||
|
// permissions and trigger macaroon regeneration on startup.
|
||||||
|
err = net.RestartNode(
|
||||||
|
net.Alice, nil, []LitArgOption{
|
||||||
|
WithLitArg("bake-super-macaroon", "read-write"),
|
||||||
|
WithLitArg("super-macaroon-path", superMacPath),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
require.NoError(t.t, err)
|
||||||
|
|
||||||
|
require.FileExists(t.t, superMacPath)
|
||||||
|
verifyMacaroonSubserverPermissions(superMacPath, true)
|
||||||
|
|
||||||
|
// Verify permissions: write should succeed.
|
||||||
|
verifyMacaroonPermissions(superMacPath, true)
|
||||||
|
|
||||||
|
// Clean up the super macaroon file.
|
||||||
|
_ = os.Remove(superMacPath)
|
||||||
|
|
||||||
|
// Restart Alice with super macaroon baking disabled and verify that
|
||||||
|
// no super macaroon is created.
|
||||||
|
err = net.RestartNode(
|
||||||
|
net.Alice, nil, []LitArgOption{
|
||||||
|
WithLitArg("bake-super-macaroon", "none"),
|
||||||
|
WithLitArg("super-macaroon-path", superMacPath),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
require.NoError(t.t, err)
|
||||||
|
|
||||||
|
_, err = os.Stat(superMacPath)
|
||||||
|
require.True(t.t, os.IsNotExist(err))
|
||||||
|
|
||||||
|
// Clean up after ourselves.
|
||||||
|
err = net.RestartNode(
|
||||||
|
net.Alice, nil, []LitArgOption{
|
||||||
|
WithoutLitArg("bake-super-macaroon"),
|
||||||
|
WithoutLitArg("super-macaroon-path"),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
require.NoError(t.t, err)
|
||||||
|
net.ConnectNodes(t.t, net.Alice, net.Bob)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,4 +31,8 @@ var allTestCases = []*testCase{
|
||||||
name: "kvdb to sql migration",
|
name: "kvdb to sql migration",
|
||||||
test: testKvdbSQLMigration,
|
test: testKvdbSQLMigration,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "terminal super macaroon on startup",
|
||||||
|
test: testSuperMacaroonOnStartup,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue