From 3975e83006f8d466bb089275283318f52cc9080e Mon Sep 17 00:00:00 2001 From: cyberguru1 Date: Sat, 13 Jun 2026 18:24:33 -0500 Subject: [PATCH 1/5] macaroons: add super macaroon helpers Introduce helper functions in the macaroons package to manage super macaroon files and permissions. Add SuperMacaroonExists, MacaroonMatchesPermissions, and BakeAndWriteSuperMacaroon. --- macaroons/super_mac.go | 128 ++++++++++++++++++++++++++++++++++++ macaroons/super_mac_test.go | 122 ++++++++++++++++++++++++++++++++++ 2 files changed, 250 insertions(+) diff --git a/macaroons/super_mac.go b/macaroons/super_mac.go index 32cad9ff..d103306e 100644 --- a/macaroons/super_mac.go +++ b/macaroons/super_mac.go @@ -6,8 +6,12 @@ import ( "encoding/binary" "encoding/hex" "errors" + "fmt" + "os" + "strings" "github.com/lightningnetwork/lnd/lnrpc" + "google.golang.org/protobuf/proto" "gopkg.in/macaroon-bakery.v2/bakery" "gopkg.in/macaroon.v2" ) @@ -118,3 +122,127 @@ func BakeSuperMacaroon(ctx context.Context, lnd lnrpc.LightningClient, return hex.EncodeToString(macBytes), err } + +// SuperMacaroonExists determines whether a macaroon file exists at the given +// path. +func SuperMacaroonExists(path string) bool { + if _, err := os.Stat(path); err != nil { + return false + } + + return true +} + +// MacaroonMatchesPermissions checks if the macaroon at the given path contains +// exactly the expected permissions (no more and no less). +func MacaroonMatchesPermissions(path string, + expectedPerms []bakery.Op) (bool, error) { + + macBytes, err := os.ReadFile(path) + if err != nil { + return false, err + } + + mac := &macaroon.Macaroon{} + if err := mac.UnmarshalBinary(macBytes); err != nil { + return false, err + } + + rawID := mac.Id() + if len(rawID) == 0 || rawID[0] != byte(bakery.LatestVersion) { + return false, errors.New("invalid macaroon version") + } + + decodedID := &lnrpc.MacaroonId{} + if err := proto.Unmarshal(rawID[1:], decodedID); err != nil { + return false, err + } + + // Map expected permissions for easy lookup: entity -> action -> true. + expectedMap := make(map[string]map[string]bool) + for _, op := range expectedPerms { + if expectedMap[op.Entity] == nil { + expectedMap[op.Entity] = make(map[string]bool) + } + + expectedMap[op.Entity][op.Action] = true + } + + // Map actual permissions from decoded macaroon ID: + // entity -> action -> true. + actualMap := make(map[string]map[string]bool) + for _, op := range decodedID.Ops { + if op == nil { + continue + } + if actualMap[op.Entity] == nil { + actualMap[op.Entity] = make(map[string]bool) + } + for _, action := range op.Actions { + actualMap[op.Entity][action] = true + } + } + + // Compare the mapped sets for exact equality. + if len(expectedMap) != len(actualMap) { + return false, nil + } + + for entity, actions := range expectedMap { + actualActions, ok := actualMap[entity] + + if !ok || len(actions) != len(actualActions) { + return false, nil + } + for action := range actions { + if !actualActions[action] { + return false, nil + } + } + } + + return true, nil +} + +// BakeAndWriteSuperMacaroon bakes a super macaroon and writes it to disk. +func BakeAndWriteSuperMacaroon(ctx context.Context, lnd lnrpc.LightningClient, + path string, perms []bakery.Op) error { + + var suffixBytes [4]byte + rootKeyID := NewSuperMacaroonRootKeyID(suffixBytes) + + superMacHex, err := BakeSuperMacaroon( + ctx, lnd, rootKeyID, perms, nil, + ) + if err != nil { + return fmt.Errorf("unable to bake super macaroon: %w", err) + } + + superMacBytes, err := hex.DecodeString(superMacHex) + if err != nil { + return fmt.Errorf("unable to decode baked "+ + "super macaroon: %w", err) + } + + if err := os.WriteFile(path, superMacBytes, 0600); err != nil { + return fmt.Errorf("unable to write super macaroon to %v: %w", + path, err) + } + + return nil +} + +// HasMacaroonSuffix checks that the super macaroon path is not empty and ends +// with the expected suffix. +func HasMacaroonSuffix(path string) error { + if path == "" { + return fmt.Errorf("super-macaroon-path cannot be empty") + } + + if !strings.HasSuffix(path, ".macaroon") { + return fmt.Errorf("super-macaroon-path must end with the " + + ".macaroon suffix") + } + + return nil +} diff --git a/macaroons/super_mac_test.go b/macaroons/super_mac_test.go index d4b91aea..a751683f 100644 --- a/macaroons/super_mac_test.go +++ b/macaroons/super_mac_test.go @@ -1,9 +1,13 @@ package macaroons import ( + "encoding/hex" + "os" + "path/filepath" "testing" "github.com/stretchr/testify/require" + "gopkg.in/macaroon-bakery.v2/bakery" ) var ( @@ -43,3 +47,121 @@ func TestIsSuperMacaroon(t *testing.T) { require.True(t, IsSuperMacaroon(testMacHex)) } + +// TestSuperMacaroonHelpers tests that SuperMacaroonExists and +// MacaroonMatchesPermissions behave correctly. +func TestSuperMacaroonHelpers(t *testing.T) { + t.Parallel() + + tempDir := t.TempDir() + path := filepath.Join(tempDir, "test.macaroon") + + // Verify that it doesn't exist yet. + require.False(t, SuperMacaroonExists(path)) + + // Write the test macaroon. + macBytes, err := hex.DecodeString(testMacHex) + require.NoError(t, err) + err = os.WriteFile(path, macBytes, 0600) + require.NoError(t, err) + + // Now it should exist. + require.True(t, SuperMacaroonExists(path)) + + // The macaroon matches this expected list of permissions. + expectedPerms := []bakery.Op{ + {Entity: "account", Action: "read"}, + {Entity: "auction", Action: "read"}, + {Entity: "audit", Action: "read"}, + {Entity: "auth", Action: "read"}, + {Entity: "info", Action: "read"}, + {Entity: "insights", Action: "read"}, + {Entity: "invoices", Action: "read"}, + {Entity: "loop", Action: "in"}, + {Entity: "loop", Action: "out"}, + {Entity: "macaroon", Action: "read"}, + {Entity: "message", Action: "read"}, + {Entity: "offchain", Action: "read"}, + {Entity: "onchain", Action: "read"}, + {Entity: "order", Action: "read"}, + {Entity: "peers", Action: "read"}, + {Entity: "rates", Action: "read"}, + {Entity: "recommendation", Action: "read"}, + {Entity: "report", Action: "read"}, + {Entity: "suggestions", Action: "read"}, + {Entity: "swap", Action: "read"}, + {Entity: "terms", Action: "read"}, + } + + matches, err := MacaroonMatchesPermissions(path, expectedPerms) + require.NoError(t, err) + require.True(t, matches) + + // A subset of permissions should NOT match exactly. + matches, err = MacaroonMatchesPermissions(path, expectedPerms[:5]) + require.NoError(t, err) + require.False(t, matches) + + // Extra/different permissions should NOT match exactly. + differentPerms := append( + expectedPerms, + bakery.Op{Entity: "invalid", Action: "write"}, + ) + matches, err = MacaroonMatchesPermissions(path, differentPerms) + require.NoError(t, err) + require.False(t, matches) +} + +// TestHasMacaroonSuffix tests that HasMacaroonSuffix correctly +// checks the suffix of the super macaroon path. +func TestHasMacaroonSuffix(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + path string + wantErr bool + errStr string + }{ + { + name: "empty path", + path: "", + wantErr: true, + errStr: "super-macaroon-path cannot be empty", + }, + { + name: "valid path", + path: "/tmp/test.macaroon", + wantErr: false, + }, + { + name: "invalid path - missing suffix", + path: "/tmp/test.mac", + wantErr: true, + errStr: "super-macaroon-path must end " + + "with the .macaroon suffix", + }, + { + name: "invalid path - wrong suffix", + path: "/tmp/test.macaroon.tmp", + wantErr: true, + errStr: "super-macaroon-path must end " + + "with the .macaroon suffix", + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + err := HasMacaroonSuffix(tt.path) + if tt.wantErr { + require.Error(t, err) + require.Contains(t, err.Error(), tt.errStr) + } else { + require.NoError(t, err) + } + }) + } +} From d3e51fac178a90b098c6151c9281ad988bb06fe0 Mon Sep 17 00:00:00 2001 From: cyberguru1 Date: Sat, 13 Jun 2026 18:24:10 -0500 Subject: [PATCH 2/5] config: add super macaroon startup flags and path validation Introduce configuration flags to enable baking a super macaroon on startup. Add --bake-super-macaroon (none, read-only, read-write) and --super-macaroon-path. Also add validation logic to ensure that the configured super macaroon path ends with the expected '.macaroon' suffix, rejecting startup early otherwise. --- config.go | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/config.go b/config.go index fc6fd7f9..038f39ef 100644 --- a/config.go +++ b/config.go @@ -27,6 +27,7 @@ import ( "github.com/lightninglabs/lightning-terminal/db/sqlc" "github.com/lightninglabs/lightning-terminal/firewall" "github.com/lightninglabs/lightning-terminal/firewalldb" + "github.com/lightninglabs/lightning-terminal/macaroons" mid "github.com/lightninglabs/lightning-terminal/rpcmiddleware" "github.com/lightninglabs/lightning-terminal/session" "github.com/lightninglabs/lightning-terminal/subservers" @@ -96,6 +97,22 @@ const ( // autogenerated lit macaroon. DefaultMacaroonFilename = "lit.macaroon" + // DefaultSuperMacaroonFilename is the default file name for the + // autogenerated super macaroon. + DefaultSuperMacaroonFilename = "super.macaroon" + + // noneChoice is the none choice for the bake-super-macaroon + // configuration option. + noneChoice = "none" + + // readOnlyChoice is the read-only choice for the bake-super-macaroon + // configuration option. + readOnlyChoice = "read-only" + + // defaultBakeSuperMacaroon is the default value for the + // bake-super-macaroon configuration option. + defaultBakeSuperMacaroon = noneChoice + defaultFirstLNCConnTimeout = 10 * time.Minute // DatabaseBackendSqlite is the name of the SQLite database backend. @@ -169,6 +186,12 @@ var ( defaultSqliteDatabasePath = filepath.Join( DefaultLitDir, DefaultNetwork, defaultSqliteDatabaseFileName, ) + + // DefaultSuperMacaroonPath is the default full path of the super + // macaroon. + DefaultSuperMacaroonPath = filepath.Join( + DefaultLitDir, DefaultNetwork, DefaultSuperMacaroonFilename, + ) ) // Config is the main configuration struct of lightning-terminal. It contains @@ -203,6 +226,9 @@ type Config struct { MacaroonPath string `long:"macaroonpath" description:"Path to write the macaroon for litd's RPC and REST services if it doesn't exist."` + BakeSuperMacaroon string `long:"bake-super-macaroon" description:"Bake a super macaroon on startup if it doesn't exist." choice:"none" choice:"read-only" choice:"read-write"` + SuperMacaroonPath string `long:"super-macaroon-path" description:"Path to write the auto-baked super macaroon. This must include both the directory and the name of the macaroon file itself (which must end with the .macaroon suffix)."` + FirstLNCConnDeadline time.Duration `long:"firstlncconndeadline" description:"The duration after a new LNC session will be revoked if no connection is made with it. This only applies for the first connection which is made using the pairing phrase. "` // DatabaseBackend is the database backend we will use for storing all @@ -543,6 +569,8 @@ func defaultConfig() *Config { LetsEncryptListen: defaultLetsEncryptListen, LetsEncryptDir: defaultLetsEncryptDir, MacaroonPath: DefaultMacaroonPath, + SuperMacaroonPath: DefaultSuperMacaroonPath, + BakeSuperMacaroon: defaultBakeSuperMacaroon, DatabaseBackend: DatabaseBackendSqlite, Sqlite: &db.SqliteConfig{ DatabaseFileName: defaultSqliteDatabasePath, @@ -732,6 +760,32 @@ func loadAndValidateConfig(ctx context.Context, return nil, err } + if cfg.BakeSuperMacaroon != defaultBakeSuperMacaroon { + if cfg.SuperMacaroonPath == DefaultSuperMacaroonPath { + cfg.SuperMacaroonPath = filepath.Join( + litDir, cfg.Network, + DefaultSuperMacaroonFilename, + ) + } + + err = macaroons.HasMacaroonSuffix( + cfg.SuperMacaroonPath, + ) + if err != nil { + return nil, err + } + + // Clean and expand the super macaroon path + cfg.SuperMacaroonPath = lncfg.CleanAndExpandPath( + cfg.SuperMacaroonPath, + ) + dir := filepath.Dir(cfg.SuperMacaroonPath) + if err := makeDirectories(dir); err != nil { + return nil, fmt.Errorf("unable to create super "+ + "macaroon directory %v: %w", dir, err) + } + } + err = cfg.DevConfig.Validate() if err != nil { return nil, err From c5fbbd4d7770fae2130faf5bdc2e364683b1e615 Mon Sep 17 00:00:00 2001 From: cyberguru1 Date: Sat, 13 Jun 2026 18:24:36 -0500 Subject: [PATCH 3/5] terminal: auto-bake super macaroon on startup Automatically bake a super macaroon on startup if it doesn't already exist on disk and the `bake-super-macaroon` option is configured. On startup, the node verifies if the super macaroon file exists. If it does, it parses the macaroon, extracts and verifies the version and root key ID, and asserts that the macaroon permissions exactly match the expected active permissions. If there is a mismatch, the macaroon is regenerated and overwritten on disk. If the file does not exist, a new super macaroon is baked and written directly to disk. Also validate that the `bake-super-macaroon` option is not enabled when LND is running in stateless initialization mode, failing startup early if they are used together. --- terminal.go | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/terminal.go b/terminal.go index c2098bd6..36746444 100644 --- a/terminal.go +++ b/terminal.go @@ -822,6 +822,13 @@ func (g *LightningTerminal) start(ctx context.Context) error { return fmt.Errorf("could not start litd sub-servers: %v", err) } + // Bake the super macaroon on startup if configured, now that all local + // and remote sub-servers have been started and active permissions are + // fully known. + if err := g.setupSuperMacaroon(ctx); err != nil { + return fmt.Errorf("could not setup super macaroon: %w", err) + } + // We can now set the status of LiT as running. g.statusMgr.SetRunning(subservers.LIT) @@ -2192,3 +2199,64 @@ func randId(n int) string { return string(b) } + +// setupSuperMacaroon bakes a super macaroon and writes it to disk if needed. +func (g *LightningTerminal) setupSuperMacaroon(ctx context.Context) error { + // If the bake-super-macaroon option is set to none, we don't bake a + // macaroon. + if g.cfg.BakeSuperMacaroon == noneChoice { + return nil + } + + // If the super macaroon baking option is enabled, we cannot run in + // stateless initialization mode as it won't write any macaroons to the + // filesystem. + if g.cfg.statelessInitMode { + return fmt.Errorf("cannot use bake-super-macaroon " + + "with stateless-init mode") + } + + path := g.cfg.SuperMacaroonPath + + readOnly := g.cfg.BakeSuperMacaroon == readOnlyChoice + activePerms := g.permsMgr.ActivePermissions(readOnly) + + if litmac.SuperMacaroonExists(path) { + matches, err := litmac.MacaroonMatchesPermissions( + path, activePerms, + ) + + if err == nil && matches { + log.Debugf("Super macaroon already exists at "+ + "%v and matches configuration, "+ + "skipping bake", path) + + return nil + } + if err != nil { + return fmt.Errorf( + "unable to verify super macaroon "+ + "permissions at %v, please delete "+ + "it if the issue persists: %w", + path, err, + ) + } + + log.Infof("Super macaroon permissions " + + "differ from configuration, " + + "regenerating...") + } + + log.Infof("Baking super macaroon on startup...") + + // Bake the super macaroon and write it to disk. + if err := litmac.BakeAndWriteSuperMacaroon( + ctx, g.basicClient, path, activePerms, + ); err != nil { + return err + } + + log.Infof("Successfully baked and wrote super macaroon to %v", path) + + return nil +} From 7cde9c50ae6b7670970e94f991cd8bff9863ffe8 Mon Sep 17 00:00:00 2001 From: cyberguru1 Date: Sat, 13 Jun 2026 18:25:10 -0500 Subject: [PATCH 4/5] 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. --- itest/litd_mode_integrated_test.go | 215 +++++++++++++++++++++++++++++ itest/litd_test_list_on_test.go | 4 + 2 files changed, 219 insertions(+) diff --git a/itest/litd_mode_integrated_test.go b/itest/litd_mode_integrated_test.go index 889fca0b..831ec07a 100644 --- a/itest/litd_mode_integrated_test.go +++ b/itest/litd_mode_integrated_test.go @@ -11,6 +11,7 @@ import ( "io/ioutil" "net/http" "os" + "path/filepath" "strings" "testing" "time" @@ -1530,3 +1531,217 @@ func bakeSuperMacaroon(t *testing.T, cfg *LitNodeConfig, 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) +} diff --git a/itest/litd_test_list_on_test.go b/itest/litd_test_list_on_test.go index eaf0f77f..ee0ba932 100644 --- a/itest/litd_test_list_on_test.go +++ b/itest/litd_test_list_on_test.go @@ -31,4 +31,8 @@ var allTestCases = []*testCase{ name: "kvdb to sql migration", test: testKvdbSQLMigration, }, + { + name: "terminal super macaroon on startup", + test: testSuperMacaroonOnStartup, + }, } From 0c06130ea1269a4040c08d01aefb6e49093f5956 Mon Sep 17 00:00:00 2001 From: cyberguru1 Date: Sat, 13 Jun 2026 18:25:14 -0500 Subject: [PATCH 5/5] docs: add release notes for super macaroon auto-bake Add release notes for the new auto-bake config options in release notes for version 0.17.1 and reference pull request #1324. --- docs/release-notes/release-notes-0.17.1.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/release-notes/release-notes-0.17.1.md b/docs/release-notes/release-notes-0.17.1.md index ce3ca83d..7046ef8a 100644 --- a/docs/release-notes/release-notes-0.17.1.md +++ b/docs/release-notes/release-notes-0.17.1.md @@ -39,6 +39,15 @@ an account, supporting pagination (sorted in ascending lexicographical order of their payment hash) and counting of total payments. +* [Auto-bake super macaroon on startup](https://github.com/lightninglabs/lightning-terminal/pull/1324): + Added config options `--bake-super-macaroon` (choice: `none`, `read-only`, + `read-write`) and `--super-macaroon-path` to automatically bake a super + macaroon on startup and keep its permissions in sync. When set to `read-only` + or `read-write`, the daemon will automatically bake a super macaroon + containing read-only or read-write permissions, respectively, for all active + sub-servers on startup. If the macaroon already exists but has different + permissions, it will be automatically regenerated. + ### Technical and Architectural Updates * [Report litd's own version for `litd