Replace NoActor runtime Mix.env with compile-time config
Use Application.compile_env for release-safety. Config only set in test.exs (defaults to false).
This commit is contained in:
parent
811a276d92
commit
05c71132e4
3 changed files with 26 additions and 42 deletions
|
|
@ -49,3 +49,7 @@ config :mv, :require_token_presence_for_authentication, false
|
||||||
# Enable SQL Sandbox for async LiveView tests
|
# Enable SQL Sandbox for async LiveView tests
|
||||||
# This flag controls sync vs async behavior in CycleGenerator after_action hooks
|
# This flag controls sync vs async behavior in CycleGenerator after_action hooks
|
||||||
config :mv, :sql_sandbox, true
|
config :mv, :sql_sandbox, true
|
||||||
|
|
||||||
|
# Allow operations without actor in test environment (NoActor check)
|
||||||
|
# SECURITY: This must ONLY be true in test.exs, never in prod/dev
|
||||||
|
config :mv, :allow_no_actor_bypass, true
|
||||||
|
|
|
||||||
|
|
@ -42,9 +42,9 @@ defmodule Mv.Authorization.Checks.NoActor do
|
||||||
use Ash.Policy.SimpleCheck
|
use Ash.Policy.SimpleCheck
|
||||||
|
|
||||||
# Compile-time check: Only allow no-actor bypass in test environment
|
# Compile-time check: Only allow no-actor bypass in test environment
|
||||||
@allow_no_actor_bypass Mix.env() == :test
|
# SECURITY: This must ONLY be true in test.exs, never in prod/dev
|
||||||
# Alternative (if you want to control via config):
|
# Using compile_env instead of Mix.env() for release-safety
|
||||||
# @allow_no_actor_bypass Application.compile_env(:mv, :allow_no_actor_bypass, false)
|
@allow_no_actor_bypass Application.compile_env(:mv, :allow_no_actor_bypass, false)
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def describe(_opts) do
|
def describe(_opts) do
|
||||||
|
|
@ -58,14 +58,9 @@ defmodule Mv.Authorization.Checks.NoActor do
|
||||||
@impl true
|
@impl true
|
||||||
def match?(nil, _context, _opts) do
|
def match?(nil, _context, _opts) do
|
||||||
# Actor is nil
|
# Actor is nil
|
||||||
# Double-check: compile-time AND runtime environment
|
# SECURITY: Only allow if compile_env flag is set (test.exs only)
|
||||||
if @allow_no_actor_bypass and Mix.env() == :test do
|
# No runtime Mix.env() check - fail-closed by default (false)
|
||||||
# Test environment: Allow all operations
|
@allow_no_actor_bypass
|
||||||
true
|
|
||||||
else
|
|
||||||
# Production/dev: Deny all operations (fail-closed for security)
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def match?(_actor, _context, _opts) do
|
def match?(_actor, _context, _opts) do
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ defmodule Mv.Authorization.Checks.NoActorTest do
|
||||||
|
|
||||||
describe "match?/3" do
|
describe "match?/3" do
|
||||||
test "returns true when actor is nil in test environment" do
|
test "returns true when actor is nil in test environment" do
|
||||||
# In test environment, NoActor should allow operations
|
# In test environment (config :allow_no_actor_bypass = true), NoActor allows operations
|
||||||
result = NoActor.match?(nil, %{}, [])
|
result = NoActor.match?(nil, %{}, [])
|
||||||
assert result == true
|
assert result == true
|
||||||
end
|
end
|
||||||
|
|
@ -22,46 +22,31 @@ defmodule Mv.Authorization.Checks.NoActorTest do
|
||||||
assert result == false
|
assert result == false
|
||||||
end
|
end
|
||||||
|
|
||||||
test "has compile-time guard preventing production use" do
|
test "uses compile-time config (not runtime Mix.env)" do
|
||||||
# The @allow_no_actor_bypass module attribute is set at compile time
|
# The @allow_no_actor_bypass is set via Application.compile_env at compile time
|
||||||
# In test: true, in prod/dev: false
|
# In test.exs: config :mv, :allow_no_actor_bypass, true
|
||||||
# This test verifies the guard exists (compile-time check)
|
# In prod/dev: not set (defaults to false)
|
||||||
# Runtime check is verified by the fact that match? checks Mix.env()
|
# This ensures the check is release-safe (no runtime Mix.env dependency)
|
||||||
result = NoActor.match?(nil, %{}, [])
|
result = NoActor.match?(nil, %{}, [])
|
||||||
|
|
||||||
# In test environment, should allow
|
# In test environment (as compiled), should allow
|
||||||
if Mix.env() == :test do
|
assert result == true
|
||||||
assert result == true
|
|
||||||
else
|
|
||||||
# In other environments, should deny
|
|
||||||
assert result == false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test "has runtime guard preventing production use" do
|
# Note: We cannot test "production mode" here because the flag is compile-time.
|
||||||
# The match? function checks Mix.env() at runtime
|
# Production safety is guaranteed by:
|
||||||
# This provides defense in depth against config drift
|
# 1. Config only set in test.exs
|
||||||
result = NoActor.match?(nil, %{}, [])
|
# 2. Default is false (fail-closed)
|
||||||
|
# 3. No runtime environment checks
|
||||||
# Should match compile-time guard
|
|
||||||
if Mix.env() == :test do
|
|
||||||
assert result == true
|
|
||||||
else
|
|
||||||
assert result == false
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "describe/1" do
|
describe "describe/1" do
|
||||||
test "returns description based on environment" do
|
test "returns description based on compile-time config" do
|
||||||
description = NoActor.describe([])
|
description = NoActor.describe([])
|
||||||
assert is_binary(description)
|
assert is_binary(description)
|
||||||
|
|
||||||
if Mix.env() == :test do
|
# In test environment (compiled with :allow_no_actor_bypass = true)
|
||||||
assert description =~ "test environment"
|
assert description =~ "test environment"
|
||||||
else
|
|
||||||
assert description =~ "production/dev"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue