-
Notifications
You must be signed in to change notification settings - Fork 0
fix: wfctl improvements and security hardening #173
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
754756d
39ef8bf
343fb05
8d0b604
678b6ed
abf1a9a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,7 @@ package module | |
| import ( | ||
| "context" | ||
| "fmt" | ||
| "log/slog" | ||
| "sync" | ||
|
|
||
| "github.com/CrisisTextLine/modular" | ||
|
|
@@ -53,14 +54,20 @@ func (m *PolicyEngineModule) Init(app modular.Application) error { | |
| m.backend = "mock" | ||
| } | ||
|
|
||
| allowStub := isTruthy(m.config["allow_stub_backends"]) | ||
|
|
||
| switch m.backend { | ||
| case "mock": | ||
| m.engine = newMockPolicyEngine() | ||
| case "opa": | ||
| endpoint, _ := m.config["endpoint"].(string) | ||
| m.engine = newOPAPolicyEngine(endpoint) | ||
| m.engine = newOPAPolicyEngine(endpoint, allowStub) | ||
| slog.Warn("WARNING: using stub policy engine — all requests will be DENIED. Set allow_stub_backends: true in config to use stub backends for testing.", | ||
| "module", m.name, "backend", "opa", "allow_stub_backends", allowStub) | ||
|
Comment on lines
+57
to
+66
|
||
| case "cedar": | ||
| m.engine = newCedarPolicyEngine() | ||
| m.engine = newCedarPolicyEngine(allowStub) | ||
| slog.Warn("WARNING: using stub policy engine — all requests will be DENIED. Set allow_stub_backends: true in config to use stub backends for testing.", | ||
| "module", m.name, "backend", "cedar", "allow_stub_backends", allowStub) | ||
|
Comment on lines
+65
to
+70
|
||
| default: | ||
| return fmt.Errorf("policy.engine %q: unsupported backend %q", m.name, m.backend) | ||
| } | ||
|
|
@@ -165,6 +172,17 @@ func (e *mockPolicyEngine) Evaluate(_ context.Context, input map[string]any) (*P | |
| }, nil | ||
| } | ||
|
|
||
| // isTruthy returns true if v is a bool true, or a string "true"/"1"/"yes". | ||
| func isTruthy(v any) bool { | ||
| switch val := v.(type) { | ||
| case bool: | ||
| return val | ||
| case string: | ||
| return val == "true" || val == "1" || val == "yes" | ||
| } | ||
| return false | ||
| } | ||
|
|
||
| func containsString(s, substr string) bool { | ||
| return len(s) >= len(substr) && (s == substr || len(substr) == 0 || | ||
| func() bool { | ||
|
|
@@ -182,16 +200,17 @@ func containsString(s, substr string) bool { | |
| // opaPolicyEngine is a stub for OPA (Open Policy Agent) integration. | ||
| // Production: POST to the OPA REST API at <endpoint>/v1/data/<policy-path>. | ||
| type opaPolicyEngine struct { | ||
| endpoint string | ||
| mu sync.RWMutex | ||
| policies map[string]string | ||
| endpoint string | ||
| allowStub bool | ||
| mu sync.RWMutex | ||
| policies map[string]string | ||
| } | ||
|
|
||
| func newOPAPolicyEngine(endpoint string) *opaPolicyEngine { | ||
| func newOPAPolicyEngine(endpoint string, allowStub bool) *opaPolicyEngine { | ||
| if endpoint == "" { | ||
| endpoint = "http://localhost:8181" | ||
| } | ||
| return &opaPolicyEngine{endpoint: endpoint, policies: make(map[string]string)} | ||
| return &opaPolicyEngine{endpoint: endpoint, allowStub: allowStub, policies: make(map[string]string)} | ||
| } | ||
|
|
||
| func (e *opaPolicyEngine) LoadPolicy(name, content string) error { | ||
|
|
@@ -215,9 +234,16 @@ func (e *opaPolicyEngine) ListPolicies() []PolicyInfo { | |
| func (e *opaPolicyEngine) Evaluate(_ context.Context, input map[string]any) (*PolicyDecision, error) { | ||
| // Production: POST {"input": input} to <endpoint>/v1/data/<default-policy> | ||
| // and parse the result body for {"result": {"allow": true}}. | ||
| if e.allowStub { | ||
| return &PolicyDecision{ | ||
| Allowed: true, | ||
| Reasons: []string{"opa stub: allow_stub_backends enabled"}, | ||
| Metadata: map[string]any{"backend": "opa", "endpoint": e.endpoint, "input": input}, | ||
| }, nil | ||
| } | ||
| return &PolicyDecision{ | ||
| Allowed: true, | ||
| Reasons: []string{"opa stub: default allow"}, | ||
| Allowed: false, | ||
| Reasons: []string{"STUB IMPLEMENTATION - not connected to real backend - denied for safety"}, | ||
| Metadata: map[string]any{"backend": "opa", "endpoint": e.endpoint, "input": input}, | ||
| }, nil | ||
|
Comment on lines
234
to
248
|
||
| } | ||
|
|
@@ -227,12 +253,13 @@ func (e *opaPolicyEngine) Evaluate(_ context.Context, input map[string]any) (*Po | |
| // cedarPolicyEngine is a stub for Cedar policy language integration. | ||
| // Production: use the cedar-go library (github.com/cedar-policy/cedar-go). | ||
| type cedarPolicyEngine struct { | ||
| mu sync.RWMutex | ||
| policies map[string]string | ||
| allowStub bool | ||
| mu sync.RWMutex | ||
| policies map[string]string | ||
| } | ||
|
|
||
| func newCedarPolicyEngine() *cedarPolicyEngine { | ||
| return &cedarPolicyEngine{policies: make(map[string]string)} | ||
| func newCedarPolicyEngine(allowStub bool) *cedarPolicyEngine { | ||
| return &cedarPolicyEngine{allowStub: allowStub, policies: make(map[string]string)} | ||
| } | ||
|
|
||
| func (e *cedarPolicyEngine) LoadPolicy(name, content string) error { | ||
|
|
@@ -256,9 +283,16 @@ func (e *cedarPolicyEngine) ListPolicies() []PolicyInfo { | |
| func (e *cedarPolicyEngine) Evaluate(_ context.Context, input map[string]any) (*PolicyDecision, error) { | ||
| // Production: build a cedar.Request from input (principal, action, resource, context) | ||
| // and call policySet.IsAuthorized(request). | ||
| if e.allowStub { | ||
| return &PolicyDecision{ | ||
| Allowed: true, | ||
| Reasons: []string{"cedar stub: allow_stub_backends enabled"}, | ||
| Metadata: map[string]any{"backend": "cedar", "input": input}, | ||
| }, nil | ||
| } | ||
| return &PolicyDecision{ | ||
| Allowed: true, | ||
| Reasons: []string{"cedar stub: default allow"}, | ||
| Allowed: false, | ||
| Reasons: []string{"STUB IMPLEMENTATION - not connected to real backend - denied for safety"}, | ||
| Metadata: map[string]any{"backend": "cedar", "input": input}, | ||
| }, nil | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
STRIPE_API_KEY now enables the Stripe billing provider, but it’s constructed with an empty planPriceIDs map (billing.StripePlanIDs{}). This guarantees CreateSubscription will fail at runtime with "no stripe price ID configured" for every plan, breaking the /subscribe endpoint. Consider loading plan→price IDs from config/env (or refusing to enable Stripe until they’re configured and falling back to mock with a clear warning/error).