feat(dev): propagate INSECURE_INTERNAL=1 to compose services Maestro starts in dev mode
This commit is contained in:
@@ -18,6 +18,7 @@ package containers
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -69,6 +70,15 @@ func StartContainer(ctx context.Context, item types.RegistryContainer) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dev escape hatch (M2 §2): when Maestro itself runs with
|
||||||
|
// INSECURE_INTERNAL=1, start services the dev way too — propagate the flag
|
||||||
|
// into the compose services so infra auto-started by Maestro (e.g. a
|
||||||
|
// resurrected dcntrlized-auth, see infra.go) keeps a plaintext listener
|
||||||
|
// instead of coming up as mTLS against the plaintext dev fleet.
|
||||||
|
if os.Getenv("INSECURE_INTERNAL") == "1" {
|
||||||
|
propagateInsecureInternal(project)
|
||||||
|
}
|
||||||
|
|
||||||
// The compose file may reference the image by a short name (e.g.
|
// The compose file may reference the image by a short name (e.g.
|
||||||
// "testservice") while install pulled it under its full registry reference.
|
// "testservice") while install pulled it under its full registry reference.
|
||||||
// Make sure those short names exist so Up() can find them.
|
// Make sure those short names exist so Up() can find them.
|
||||||
@@ -161,6 +171,23 @@ func injectServiceIdentity(ctx context.Context, project *composetypes.Project, s
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// propagateInsecureInternal injects INSECURE_INTERNAL=1 into every non-oneoff
|
||||||
|
// compose service when Maestro itself runs in dev mode (the same flag the dev
|
||||||
|
// debug composes set). Mirroring those composes keeps peer edges plaintext, so
|
||||||
|
// a service auto-installed and started by Maestro (e.g. a resurrected
|
||||||
|
// dcntrlized-auth) matches the compose-managed plaintext dev fleet instead of
|
||||||
|
// binding an mTLS listener the satellites cannot reach.
|
||||||
|
func propagateInsecureInternal(project *composetypes.Project) {
|
||||||
|
for name, s := range project.Services {
|
||||||
|
if isOneoff(s) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
s.Environment = mergeEnv(s.Environment, map[string]string{"INSECURE_INTERNAL": "1"})
|
||||||
|
project.Services[name] = s
|
||||||
|
}
|
||||||
|
logger.Info("Dev mode (INSECURE_INTERNAL=1): propagated plaintext escape hatch to %d service(s)", len(project.Services))
|
||||||
|
}
|
||||||
|
|
||||||
// pinAuthFingerprint returns the service's pinned auth fingerprint, fetching
|
// pinAuthFingerprint returns the service's pinned auth fingerprint, fetching
|
||||||
// and persisting it when the install record does not have one yet (M2 §5).
|
// and persisting it when the install record does not have one yet (M2 §5).
|
||||||
// Best-effort: when the auth service is unreachable, it returns "" and the
|
// Best-effort: when the auth service is unreachable, it returns "" and the
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
// Copyright (C) 2026 Dcntrlized
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published
|
||||||
|
// by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package containers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
composetypes "github.com/compose-spec/compose-go/v2/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestPropagateInsecureInternal verifies the dev escape hatch is propagated to
|
||||||
|
// every non-oneoff compose service (and only those), mirroring what the dev
|
||||||
|
// debug composes set so Maestro-started services keep plaintext peer edges.
|
||||||
|
func TestPropagateInsecureInternal(t *testing.T) {
|
||||||
|
project := &composetypes.Project{
|
||||||
|
Services: composetypes.Services{
|
||||||
|
"app": {
|
||||||
|
Environment: map[string]*string{"PORT": strptr("8080")},
|
||||||
|
},
|
||||||
|
"worker": {
|
||||||
|
Environment: nil,
|
||||||
|
},
|
||||||
|
"migrate": {
|
||||||
|
CustomLabels: map[string]string{"org.dcntrlized.oneoff": "true"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
propagateInsecureInternal(project)
|
||||||
|
|
||||||
|
for _, name := range []string{"app", "worker"} {
|
||||||
|
s := project.Services[name]
|
||||||
|
v, ok := s.Environment["INSECURE_INTERNAL"]
|
||||||
|
if !ok || v == nil || *v != "1" {
|
||||||
|
t.Errorf("service %s: expected INSECURE_INTERNAL=1, got %v", name, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s := project.Services["migrate"]
|
||||||
|
if _, ok := s.Environment["INSECURE_INTERNAL"]; ok {
|
||||||
|
t.Error("oneoff migrate service must not receive the plaintext escape hatch")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func strptr(s string) *string { return &s }
|
||||||
Reference in New Issue
Block a user