Skip to content

Commit

Permalink
Adds the ability to deny certain trigger subjects for functions (#285)
Browse files Browse the repository at this point in the history
* Adds the ability to deny certain trigger subjects for functions

* remove debug

* comma
  • Loading branch information
autodidaddict authored Jun 20, 2024
1 parent 5e86e25 commit 848ec31
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 2 deletions.
4 changes: 3 additions & 1 deletion internal/models/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ const (
)

var (
DefaultWorkloadTypes = []controlapi.NexWorkload{controlapi.NexWorkloadNative}
RequiredTriggerSubjectDenyList = []string{"$SYS.>", "$JS.>", "$NEX.>"}
DefaultWorkloadTypes = []controlapi.NexWorkload{controlapi.NexWorkloadNative}

DefaultBinPath = append([]string{"/usr/local/bin"}, filepath.SplitList(os.Getenv("PATH"))...)

Expand Down Expand Up @@ -63,6 +64,7 @@ type NodeConfiguration struct {
Tags map[string]string `json:"tags,omitempty"`
ValidIssuers []string `json:"valid_issuers,omitempty"`
WorkloadTypes []controlapi.NexWorkload `json:"workload_types,omitempty"`
DenyTriggerSubjects []string `json:"deny_trigger_subjects,omitempty"`

// Public NATS server options; when non-nil, a public "userland" NATS server is started during node init
PublicNATSServer *server.Options `json:"public_nats_server,omitempty"`
Expand Down
7 changes: 7 additions & 0 deletions internal/node/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"os"
"path/filepath"
"runtime"
"slices"
"strings"

controlapi "github.com/synadia-io/nex/control-api"
Expand Down Expand Up @@ -49,5 +50,11 @@ func LoadNodeConfiguration(configFilepath string) (*models.NodeConfiguration, er
config.Tags = make(map[string]string)
}

for _, sub := range models.RequiredTriggerSubjectDenyList {
if !slices.Contains(config.DenyTriggerSubjects, sub) {
config.DenyTriggerSubjects = append(config.DenyTriggerSubjects, sub)
}
}

return &config, nil
}
20 changes: 20 additions & 0 deletions internal/node/controlapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"strings"
"time"

"github.com/nats-io/nats-server/v2/server"
"github.com/nats-io/nats.go"
"github.com/nats-io/nkeys"
"github.com/pkg/errors"
Expand Down Expand Up @@ -250,6 +251,16 @@ func (api *ApiListener) handleDeploy(m *nats.Msg) {
return
}

if len(request.TriggerSubjects) > 0 && len(api.node.config.DenyTriggerSubjects) > 0 {
for _, subject := range request.TriggerSubjects {
if inDenyList(subject, api.node.config.DenyTriggerSubjects) {
respondFail(controlapi.RunResponseType, m,
fmt.Sprintf("The trigger subject %s overlaps with subject(s) in this node's deny list", subject))
return
}
}
}

err = request.DecryptRequestEnvironment(api.xk)
if err != nil {
publicKey, _ := api.xk.PublicKey()
Expand Down Expand Up @@ -601,6 +612,15 @@ func myUptime(d time.Duration) string {
return fmt.Sprintf("%ds", tsecs)
}

func inDenyList(subject string, denyList []string) bool {
for _, target := range denyList {
if server.SubjectsCollide(subject, target) {
return true
}
}
return false
}

func respondFail(responseType string, m *nats.Msg, reason string) {
env := controlapi.NewEnvelope(responseType, []byte{}, &reason)
jenv, _ := json.Marshal(env)
Expand Down
19 changes: 19 additions & 0 deletions internal/node/controlapi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,25 @@ import (
controlapi "github.com/synadia-io/nex/control-api"
)

func TestDenyList(t *testing.T) {
denyList := []string{
"$SYS.>",
"$JS.>",
}

if !inDenyList("$SYS.this.is.a.test", denyList) {
t.Fatal("Should have subject collision in deny list but didn't")
}

if !inDenyList("$JS.foo.bar", denyList) {
t.Fatal("Should have subject collision in deny list but didn't")
}

if inDenyList("bob.test", denyList) {
t.Fatalf("Allowed subject was denied incorrectly")
}
}

func TestSummarizeMachinesForPing(t *testing.T) {
workloads := []controlapi.MachineSummary{
{
Expand Down
4 changes: 3 additions & 1 deletion internal/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,9 @@ func (n *Node) init() error {
n.log.Error("Failed to load node configuration file", slog.Any("err", _err), slog.String("config_path", n.nodeOpts.ConfigFilepath))
err = errors.Join(err, _err)
} else {
n.log.Info("Loaded node configuration", slog.String("config_path", n.nodeOpts.ConfigFilepath))
n.log.Info("Loaded node configuration",
slog.String("config_path", n.nodeOpts.ConfigFilepath),
)
}

n.telemetry, _err = observability.NewTelemetry(n.ctx, n.log, n.config, n.publicKey)
Expand Down

0 comments on commit 848ec31

Please sign in to comment.